revoke命令基本语法为revoke priv_type on db.table from 'user'@'host',必须严格指定权限类型、作用对象和用户账号,缺一不可;权限范围、用户名及主机名须与原始grant完全一致,否则报错或无效。

revoke 命令的基本语法和必须指定的范围
MySQL 的 REVOKE 不是“撤销所有权限”的模糊操作,它必须精确到权限类型、作用对象(库/表/列)和用户账号。漏掉任意一项,命令会报错或不起作用。
常见错误现象:ERROR 1141 (42000): There is no such grant defined for user 'u1' on host '%',通常是因为权限范围(比如 ON db1.*)和当初 GRANT 时写的不一致。
- 权限名必须和
GRANT时完全一致,比如SELECT、INSERT、UPDATE,不能写成select(大小写敏感) - 作用对象必须匹配:如果当初授的是
ON test.t1,就不能用ON test.*来撤销 - 用户名和 host 必须完整,比如
'u1'@'192.168.1.%'和'u1'@'%'是两个不同账号
撤销特定表上的部分权限(不是整库)
很多用户误以为 REVOKE INSERT ON test.* FROM 'u1'@'%' 会删掉 test.t1 上的 INSERT,其实它只影响库级权限;若当初是针对单表授权的,必须回到原粒度撤销。
示例:假设执行过 GRANT UPDATE, DELETE ON test.orders TO 'u1'@'%',现在只想收回 DELETE:
REVOKE DELETE ON test.orders FROM 'u1'@'%';
注意:UPDATE 权限不受影响,仍保留;但若该用户还通过角色或其他账号继承了 DELETE,仅这条命令无法覆盖。
- 不能用
REVOKE ALL PRIVILEGES ON test.orders来“清空”,因为这会连SELECT等其他权限也撤掉(除非你真想这样) - 撤销后需执行
FLUSH PRIVILEGES;才生效——仅在直接修改mysql系统表后才强制需要,正常用REVOKE命令不用,但加了也不报错,建议加上以防旧版本行为
撤销列级权限时容易忽略的细节
列级权限(如只给某几列 UPDATE)撤销时,列名列表必须和 GRANT 时完全一致,顺序无关,但少一个都不行。
例如,当初执行了:GRANT UPDATE(col_a, col_b) ON test.users TO 'u1'@'%',现在要收回对 col_b 的更新权:
REVOKE UPDATE(col_b) ON test.users FROM 'u1'@'%';
此时 col_a 的 UPDATE 权限仍保留。但如果误写成 REVOKE UPDATE(col_c),MySQL 会静默忽略(不报错),因为该列原本就没授权。
- 列级权限无法跨表撤销,
REVOKE UPDATE(col_a) ON test.*是非法语法 - 用
SHOW GRANTS FOR 'u1'@'%'查看当前实际生效的权限,比凭记忆更可靠
撤销权限后连接未立即失效?检查权限缓存和生效时机
用户当前已建立的连接不会立刻丢失权限,新权限规则只对后续新建连接生效。这是 MySQL 的设计,不是 bug。
如果你刚 REVOKE 完就用同一连接测试,仍能执行被撤销的操作——因为权限在连接初始化时已加载进内存。
- 验证是否生效,应新开一个客户端连接再测试
- 如果应用使用连接池,可能复用旧连接数分钟,需重启池或等待连接老化
-
REVOKE操作本身很快,但权限变更传播无“广播机制”,依赖客户端主动重连
真正难处理的是嵌套权限来源:用户可能从角色继承权限,或通过 WITH GRANT OPTION 被其他账号间接授予权限。单靠查 SHOW GRANTS 不够,得结合 mysql.role_edges 和 mysql.proxies_priv 表排查。











