不能直接 DROP USER,必须先用 REVOKE 逐层回收权限,再删账号;否则残留的权限记录可能在下次 FLUSH PRIVILEGES 后意外复活。因为 MySQL 权限分散存储于 mysql.user、mysql.db、mysql.tables_priv 等多张表,DROP USER 仅删除 user 表主记录,不清理其他表中该用户的显式授权,这些“幽灵权限”在刷新后可能重新生效。

不能直接 DROP USER,必须先用 REVOKE 逐层回收权限,再删账号;否则残留的权限记录可能在下次 FLUSH PRIVILEGES 后意外复活。
为什么不能直接 DROP USER 就完事
MySQL 的权限不是“绑定在用户身上”,而是分散存在 mysql.user、mysql.db、mysql.tables_priv 等多张表里。DROP USER 只删 user 表主记录,但若该用户曾在其他权限表中被显式授权(比如通过 GRANT SELECT ON testdb.t1 TO 'dba_old'@'%'),那些记录不会自动清除。一旦执行 FLUSH PRIVILEGES,这些“幽灵权限”就可能重新生效——尤其在 MySQL 5.7 或某些配置下。
常见错误现象:DROP USER 'dba_old'@'%' 执行成功,但过两天发现该账号仍能连上并查某个库,就是这个原因。
- 必须先查清该账号所有权限来源:
SELECT * FROM mysql.db WHERE User = 'dba_old';、SELECT * FROM mysql.tables_priv WHERE User = 'dba_old'; - MySQL 8.0+ 支持
SHOW GRANTS FOR 'dba_old'@'%',但只显示显式 GRANT 记录,不反映 db 表等隐式授权 - 别依赖“没看到 GRANT 就等于没权限”——权限验证是按层级顺序匹配的,哪怕 user 表没权限,db 表有也能过
REVOKE 必须严格匹配当初的 GRANT 语句
MySQL 的权限撤销不是“一键清空”,而是“逆向还原”。你当初怎么给的,现在就得怎么撤。比如:
- 如果当初执行了
GRANT SELECT, INSERT ON app_db.* TO 'dba_old'@'192.168.1.%',就必须用REVOKE SELECT, INSERT ON app_db.* FROM 'dba_old'@'192.168.1.%' - 如果当初给了全局权限
GRANT PROCESS ON *.* TO 'dba_old'@'%',就不能只写REVOKE PROCESS ON app_db.*——范围不一致,语句会报错或无效 - MySQL 8.0 不支持
REVOKE ALL PRIVILEGES撤销列级权限,必须单独对columns_priv表执行 DELETE(且需手动 FLUSH)
容易踩的坑:用 REVOKE ALL ON *.* FROM 'dba_old'@'%' 想一步到位,结果只清了全局权限,db 表里的库级权限纹丝不动。
交接前必须确认的三类残留风险
离职 DBA 账号往往不止有常规权限,还有容易被忽略的高危残留:
-
GRANT OPTION:若该账号曾被授过此权限,它可能已转授给其他人。得查SELECT * FROM mysql.user WHERE Grant_priv = 'Y',顺藤摸瓜清理下游账号 - 角色(Role):MySQL 8.0+ 中,若账号被赋予了角色(如
SET DEFAULT ROLE admin_role TO 'dba_old'@'%'),仅REVOKE权限不够,还得DROP ROLE或REVOKE ROLE ... FROM - 存储过程/函数的 DEFINER:检查
SELECT name, definer FROM mysql.proc WHERE definer LIKE 'dba_old@%',否则这些对象后续执行仍以原账号身份运行,权限继承风险仍在
性能影响:批量查权限表(尤其是 tables_priv)在大库上可能慢,建议先用 SELECT COUNT(*) 预估规模,避免阻塞。
删账号前最后一步:强制踢出活跃连接
权限收回后,账号可能还在跑长事务或空闲连接,新权限不会自动应用到已有会话。必须主动终止:
- 查连接:
SELECT ID, USER, HOST, COMMAND, TIME FROM information_schema.PROCESSLIST WHERE USER = 'dba_old'; - 逐个杀:
KILL <code>ID;(注意不是KILL CONNECTION,老版本不支持) - MySQL 5.7+ 可用
KILL USER 'dba_old'@'%'一键杀光(但不兼容 5.6)
容易被忽略的地方:有些 DBA 会建多个同名不同 host 的账号(如 'dba_old'@'192.168.1.100' 和 'dba_old'@'10.0.0.%'),漏掉一个 host 就等于留了一扇没锁的门。务必用 SELECT user, host FROM mysql.user WHERE user = 'dba_old'; 兜底核对。


















