delete或drop user后连接仍有效是正常行为,因mysql权限只在连接建立时加载一次,已存在会话保留原权限快照,需客户端断开重连才能生效;drop user自动清理全部权限表并刷新缓存,而delete仅删mysql.user表导致残留权限。

DELETE 或 DROP USER 后连接仍有效是正常行为
MySQL 的权限检查只在连接建立时做一次,会话一旦建立,就带着当时加载的权限快照运行,后续 DROP USER 或 REVOKE 不会影响已存在的连接。这不是 bug,是设计如此——避免频繁权限变更导致连接中断或状态不一致。
常见现象包括:SHOW PROCESSLIST 里还能看到该用户活跃连接;这些连接继续执行 SELECT、INSERT 等操作;应用日志里没报错,但你明明已经删了账号。
关键点在于:权限元数据变了,但内存里的会话上下文没刷新。要让变更生效,必须让客户端断开重连。
DROP USER 和 DELETE FROM mysql.user 的实际差异
用 DROP USER 'u'@'h' 是安全做法,它会自动清理 mysql.user、mysql.db、mysql.tables_priv、mysql.columns_priv、mysql.proxies_priv 等所有关联记录,并隐式触发权限缓存更新(MySQL 5.7+)。
而直接 DELETE FROM mysql.user WHERE User = 'u' AND Host = 'h' 只删主表,其他权限表残留会导致:同名用户重建失败(报错 ERROR 1396)、新连接权限异常、甚至旧连接还能凭残留的 mysql.db 条目继续访问库。
所以别手痒去删系统表,DROP USER 就是为此设计的唯一正确入口。
如何验证用户是否真被清理干净
不能只看 SELECT * FROM mysql.user 是否为空,得查全链路:
SELECT * FROM mysql.db WHERE User = 'u' AND Host = 'h'SELECT * FROM mysql.tables_priv WHERE User = 'u' AND Host = 'h'SELECT * FROM mysql.columns_priv WHERE User = 'u' AND Host = 'h'SELECT * FROM mysql.proxies_priv WHERE User = 'u' AND Host = 'h'SELECT * FROM mysql.role_edges WHERE TO_USER = 'u' AND TO_HOST = 'h'
只要其中任一表还有匹配行,说明权限没清完。尤其注意 Host 字段必须完全一致——'u'@'localhost' 和 'u'@'127.0.0.1' 是两个独立账号。
真正容易被忽略的 DEFINDER 风险
如果被删用户是某个触发器或存储过程的 DEFINER,比如 DEFINER=`appuser`@`%`,那即使账号已删,触发器仍存在于 information_schema.TRIGGERS 中,但每次触发都会静默失败或报 Access denied for user 'appuser'@'%'。
这种问题不会导致 DML 报错,只会让业务逻辑“看起来正常却漏执行”,排查时需主动查 SHOW WARNINGS 或错误日志关键词 definer。
修复只能二选一:CREATE OR REPLACE DEFINER = CURRENT_USER TRIGGER ...(需 SUPER 权限),或先 DROP TRIGGER 再用新 DEFINER 重建——临时账号绝不该当 DEFINER。











