必须用drop user删除用户,不可直接delete from mysql.user;需验证mysql.user、mysql.db、mysql.role_edges等表无残留,并kill活跃会话、手动清理数据库对象。

必须用 DROP USER,别碰 mysql.user 表
直接 DELETE FROM mysql.user 是高危操作:它只删主表,mysql.db、mysql.tables_priv 等权限表里的记录全留着,形成悬空权限。MySQL 8.0+ 还有内存级权限缓存,删表后不 FLUSH PRIVILEGES 就连不上;即使 flush 了,也可能触发 ERROR 1396 (HY000) ——系统认为用户“还存在”,但查 mysql.user 又找不到。
DROP USER 后权限还在?先查 mysql.db 和 mysql.role_edges
DROP USER 本身会自动清理所有权限表,但若之前手动删过表或从老版本升级,残留仍可能出现。必须立刻验证:
-
SELECT User, Host FROM mysql.user WHERE User = 'u' AND Host = 'h';—— 必须为空 -
SELECT * FROM mysql.db WHERE User = 'u' AND Host = 'h';(同样查mysql.tables_priv、mysql.columns_priv)—— 这些也必须为空 - MySQL 8.0+ 特别要查角色边:
SELECT * FROM mysql.role_edges WHERE FROM_USER = 'u' AND FROM_HOST = 'h';,有返回就得手动DELETE并FLUSH PRIVILEGES
删完用户,连接还在?KILL 活跃会话不是可选,是必须
DROP USER 不中断已有连接,旧权限在当前会话中依然有效,直到断开。这期间可能执行越权操作,尤其当应用使用长连接池时。
- 查活跃连接:
SELECT ID, USER, HOST FROM information_schema.PROCESSLIST WHERE USER = 'u'; - 生成并执行杀连接语句:
SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist WHERE user = 'u'; - 注意:
KILL 1234是终止会话,不是KILL CONNECTION 1234(后者在 5.7+ 已弃用)
删用户不等于删数据,DROP DATABASE 得另起炉灶
DROP USER 只动权限元数据,完全不管用户建的库、表、函数。比如 app@% 建了库 app_data,删用户后该库原样保留。
- 确认归属:
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'app_data'; - 手动删库:
DROP DATABASE IF EXISTS app_data; - 注意:若其他账号仍有对该库的权限(如
GRANT SELECT ON app_data.* TO 'reporter'@'%'),删库后这些权限变成ON non_existent_db.*,虽不报错但建议同步清理
真正容易被忽略的是:删用户后,应用连接池里的长连接不会断开,旧权限在——哪怕你已经跑完 DROP USER 和 FLUSH PRIVILEGES,只要连接没重连,它就还能继续用。











