REVOKE DROP必须严格匹配原始GRANT的ON子句,包括反引号、大小写、库名和host;MySQL 8.0+需单独REVOKE TRUNCATE权限,否则TRUNCATE仍可执行。

REVOKE DROP 必须完全匹配原始 GRANT 的 ON 子句
执行 REVOKE DROP ON db_name.* FROM 'user'@'host' 报错 ERROR 1141 (42000): There is no such grant defined for user,几乎全是 ON 子句不一致导致的。MySQL 不做模糊匹配,只认字面完全相等。
- 当初是
GRANT DROP ON `Sales`.* TO 'u'@'%'→ 必须写REVOKE DROP ON `Sales`.* FROM 'u'@'%'(反引号、大小写、库名全对) - 当初是
GRANT DROP ON *.* TO 'u'@'localhost'→ 不能缩写成REVOKE DROP ON mydb.*,必须写REVOKE DROP ON *.* FROM 'u'@'localhost' - 用户有多个 host 记录(如
'u'@'localhost'和'u'@'127.0.0.1'),需分别执行REVOKE,漏一条就白干
TRUNCATE 权限在 MySQL 8.0+ 需单独回收
MySQL 8.0 开始,TRUNCATE TABLE 不再隐式依赖 DROP,而是独立权限项。只撤 DROP 无法阻止 TRUNCATE,必须显式加一条:
-
REVOKE TRUNCATE ON db_name.tbl_name FROM 'u'@'host'(表级) -
REVOKE TRUNCATE ON db_name.* FROM 'u'@'host'(库级) -
REVOKE TRUNCATE ON *.* FROM 'u'@'host'(全局) - 旧版 MySQL(TRUNCATE 由
DROP权限覆盖,但若用户有DELETE+CREATE,仍可能绕过——得一并检查
当前连接不生效,必须主动清理或重连
REVOKE 成功只更新服务端权限表,已建立的连接(包括应用连接池里的长连接)仍用旧权限快照。用户执行 DROP TABLE 还会成功,直到断开。
- 查活跃连接:
SHOW PROCESSLIST,找对应User和Host - 踢掉连接:
KILL CONNECTION <code>id(注意不是KILL QUERY) - 若用连接池(如 HikariCP),需重启应用或触发连接重建;单纯
FLUSH PRIVILEGES对已存在连接无效 - 角色继承权限更麻烦:即使
REVOKE了用户直授权限,若其通过角色获得DROP,还得REVOKE role_name FROM 'u'@'host'
单靠 REVOKE 无法真正防住误删
收回 DROP 和 TRUNCATE 后,用户仍可能用其他方式破坏数据:
-
ALTER TABLE t RENAME TO t_bak+CREATE TABLE t→ 需同步REVOKE ALTER ON db_name.tbl_name FROM 'u'@'host' -
INSERT ... SELECT导出后删原表 → 若有SELECT+DROP(已被收),但若有CREATE+INSERT,仍可重建空表 - 持有
SUPER或SYSTEM_VARIABLES_ADMIN可禁用 binlog 直接 DDL,REVOKE DROP对其完全无效 - 真正安全的做法是:用
mysqldump --no-create-info导出数据,TRUNCATE清空(只需TRUNCATE权限),或由低权账号建空库、高权账号导入
真正难的不是写对那条 REVOKE,而是确认所有路径都被堵死——包括角色继承、多 host 账号、连接池残留、以及那些不走 DROP 却一样能清空数据的操作。


















