mysql中revoke必须严格匹配原始grant的权限名、作用对象和用户账号,三者缺一不可;写错任意项将导致静默失败或报错,无法部分生效。

必须显式写出要撤销的权限名、作用对象和用户账号,三者缺一不可;写错任意一项都会导致静默失败或报错,而不是“部分生效”。
REVOKE语句必须严格匹配原始GRANT
MySQL不会自动推导权限范围,REVOKE SELECT ON db1.* FROM 'u1'@'localhost' 只会撤掉当初用完全相同语句授予的权限。如果原始授权是 GRANT SELECT, UPDATE ON db1.t1 FROM 'u1'@'localhost',那这条 REVOKE 就完全无效——因为对象粒度(db1.* vs db1.t1)不一致。
- 先运行
SHOW GRANTS FOR 'u1'@'localhost',逐字比对ON后面的内容 - 权限名大小写敏感:
SELECT正确,select报错ERROR 1064 - 表名含特殊字符(如横线、空格)必须用反引号:
REVOKE INSERT ON `my-db`.`log_table` FROM 'u1'@'localhost' - 用户主机名必须完全一致:
'u1'@'localhost'和'u1'@'127.0.0.1'是两个独立账号,需分别处理
只撤一项权限,UPDATE不受影响的前提是它被单独授予
假设用户当前权限来自 GRANT SELECT, UPDATE ON db1.* TO 'u1'@'localhost',那么执行 REVOKE SELECT ON db1.* FROM 'u1'@'localhost' 后,UPDATE 仍保留。但如果当初是分两次授的:GRANT SELECT ON db1.* TO 'u1'@'localhost' + GRANT UPDATE ON db1.* TO 'u1'@'localhost',效果一样。
- 不能靠
REVOKE ALL PRIVILEGES ON db1.*来“留 UPDATE”,它会把所有已授的权限全清掉 -
ALL PRIVILEGES不包含GRANT OPTION或PROCESS,这些必须单独写进REVOKE语句 - MySQL 8.0+ 若用户通过角色获得权限,
SHOW GRANTS会显示AS role_name,此时直接REVOKE SELECT无效,得先REVOKE role_name FROM 'u1'@'localhost'
撤销后旧连接仍能执行原操作
执行 REVOKE 成功返回 Query OK,不代表应用立刻失效。已建立的连接(尤其是连接池里的长连接)仍持有授权快照,SELECT 还能跑,DROP 还能删,直到断开重连。
- 验证是否真生效,唯一可靠方式是:新开一个连接测试,例如
mysql -u u1 -h localhost -D db1 -e "SELECT 1" - 生产环境建议滚动重启应用或强制刷新连接池,否则权限变更形同虚设
- 不要依赖
FLUSH PRIVILEGES——它对REVOKE命令非必需,加了也不报错,但解决不了连接缓存问题
列级或表级权限容易漏查
想撤掉用户对 users.name 字段的 UPDATE 权限,不能只看 SHOW GRANTS。列级权限存在 mysql.columns_priv 表里,SHOW GRANTS 默认不显示。
- 查真实列权限:
SELECT * FROM mysql.columns_priv WHERE User='u1' AND Host='localhost' AND Db='db1' AND Table_name='users' AND Column_name='name' - 撤销必须带列名:
REVOKE UPDATE(name) ON db1.users FROM 'u1'@'localhost' - 即使撤掉了列级权限,若用户还有整表
UPDATE权限,照样能改该字段——得同步检查并处理更高层级权限 - 残留权限还可能来自
mysql.tables_priv(表级)、mysql.db(库级)甚至角色继承,需分层排查











