revoke drop权限必须严格匹配grant时的on范围,否则报错error 1141;须同步撤销alter、create、truncate等关联权限,并执行flush privileges验证生效。

REVOKE DROP 权限必须匹配 GRANT 时的 ON 范围
直接执行 REVOKE DROP ON *.* FROM 'user'@'host' 只能撤掉全局权限;如果当初是用 GRANT DROP ON mydb.* TO 'user'@'host' 授的,就必须写 REVOKE DROP ON mydb.* FROM 'user'@'host',否则报 ERROR 1141 (42000): There is no such grant defined。MySQL 不做模糊匹配,大小写、反引号、库名表名都得一模一样。
常见踩坑点:
- 用户有多个 host 记录(如
'u'@'localhost'和'u'@'%'),漏撤一个就等于没撤 - 表名含横线或点,没加反引号:
REVOKE DROP ON `my-db`.`log_table` FROM 'u'@'%'才合法 - 误写
ON *.tbl或ON mydb.*去撤单表授权——当初是GRANT DROP ON mydb.t1,就得原样写回去
TRUNCATE 权限在 MySQL 8.0+ 需单独处理
MySQL 8.0 开始,TRUNCATE TABLE 不再复用 DROP 权限,而是独立的 TRUNCATE 权限。只撤 DROP 后,用户仍可能成功执行 TRUNCATE,只要他有该权限。
正确操作:
- MySQL 8.0+:
REVOKE TRUNCATE ON mydb.* FROM 'user'@'host' - MySQL 5.7 或更早:
TRUNCATE依赖DROP + DELETE,所以必须同时撤DROP和DELETE(否则TRUNCATE仍可能成功) - 验证是否生效:用目标用户登录后执行
TRUNCATE TABLE t1;,应报错ERROR 1142
单撤 DROP 防不住删表,还得堵 ALTER+CREATE 组合路径
用户即使没有 DROP 权限,只要持有 ALTER 和 CREATE,就能通过 ALTER TABLE t1 RENAME TO t1_bak; CREATE TABLE t1 (...) 实现逻辑删表。这种绕过方式在生产环境真实存在。
必须组合回收:
REVOKE DROP, ALTER, CREATE ON mydb.t1 FROM 'user'@'host'- 检查是否残留高危权限:
SELECT * FROM mysql.role_edges WHERE TO_USER = 'user' AND TO_HOST = 'host' - 查代理权限:
SELECT * FROM mysql.proxies_priv WHERE User = 'user' AND Host = 'host' - 特别注意
SUPER或SYSTEM_VARIABLES_ADMIN:这类权限允许关闭sql_log_bin,让 DDL 绕过 binlog 约束,REVOKE DROP对其完全无效
撤完权限后必须 FLUSH PRIVILEGES
MySQL 5.7 及更早版本不支持动态权限刷新,REVOKE 后不执行 FLUSH PRIVILEGES,权限变更不会生效。MySQL 8.0+ 默认启用动态权限,但为保险起见,仍建议显式执行。
注意:
-
FLUSH PRIVILEGES是全局命令,不需要指定用户 - 若使用 RDS 或云数据库,部分平台自动刷新,但本地部署务必手动执行
- 撤权限后立即验证,别只信命令返回 “OK” —— 登录目标账号实测
DROP TABLE和TRUNCATE TABLE
真正难的不是执行几条 REVOKE,而是确认所有权限路径都被覆盖:不同 host、不同角色继承、代理权限、高危系统权限,还有 ORM 工具自动触发的隐式操作。漏掉任意一环,防误删就形同虚设。











