mysql中drop权限不可局部撤销,必须与grant时的作用域完全一致;revoke后需用show grants验证,flush privileges非必需,且truncate可能仍成功,须组合回收drop、create、alter权限。

REVOKE DROP ON *.* 不能只撤某个库的DROP
MySQL 的 DROP 权限是按作用域绑定的,不是“开关式”可拆分的权限。你当初用 GRANT DROP ON mydb.* TO 'u1'@'%' 给的,现在就必须用 REVOKE DROP ON mydb.* FROM 'u1'@'%' 才能撤销;如果当初给的是 GRANT DROP ON *.*,那只能 REVOKE DROP ON *.*,没法只撤 mydb 的 DROP。
常见错误现象:
-
ERROR 1147 (42000): There is no such grant defined...—— 因为ON后面写的范围和当初GRANT不一致(比如授的是mydb.t1,却写mydb.*去撤) - 执行完
REVOKE后仍能删表 —— 很可能用户还持有ALTER+CREATE(可先RENAME再重建),或有SUPER权限关sql_log_bin绕过约束
SHOW GRANTS FOR 'u1'@'%' 是唯一可靠验证方式
别信 Query OK 提示,它不保证权限真被移除。必须立刻查授权记录:
SHOW GRANTS FOR 'u1'@'%';
重点看两点:
- 输出里是否还有
DROP权限项(例如GRANT DROP ON mydb.* TO ...) - 是否只剩
GRANT USAGE ON *.* TO ...(说明业务权限已清空) - 注意大小写:若
lower_case_table_names = 0,MyDB.*和mydb.*是不同对象,匹配失败就撤不掉
FLUSH PRIVILEGES 不是万能刷新开关
MySQL 8.0+ 在执行 REVOKE 时会自动更新内存权限缓存,FLUSH PRIVILEGES 实际只在直接改 mysql.user 表后才必需。但它常被误当作“让撤销生效”的必选项,导致两个问题:
- 旧连接仍持有原权限,用户未重连前删表操作照常成功
- 在高并发实例上,
FLUSH PRIVILEGES可能短暂锁表,影响业务
更稳妥的做法是:执行 REVOKE → 立即 SHOW GRANTS 验证 → 通知应用重启连接池或让用户重新登录。
撤销 DROP 后 TRUNCATE TABLE 仍可能成功
TRUNCATE TABLE 不依赖 DROP 权限,而是需要 DROP + CREATE 或仅 DELETE(取决于 MySQL 版本)。部分版本只要求 DELETE 权限就能执行 TRUNCATE,所以单撤 DROP 并不能防住清空表。
真正要阻断删/清表行为,得组合控制:
- 撤
DROP ON db_name.* - 撤
CREATE ON db_name.*(防TRUNCATE重建) - 必要时限制
ALTER(因DROP TABLE隐含在ALTER权限中)
权限回收不是一次操作就结束的事,尤其是当用户有多个 host 记录、或权限由自动化工具动态管理时,'u1'@'localhost' 和 'u1'@'%' 必须分别处理,漏一个就等于没撤干净。











