必须用 DROP USER 而非 DELETE FROM mysql.user,因后者仅删主表、留孤儿权限记录,导致缓存错乱、CREATE USER 失败;DROP USER 才能原子清理 user、db、tables_priv、proxies_priv、role_edges 等全部关联表。

用 DROP USER 而不是 DELETE FROM mysql.user
直接删 mysql.user 表是危险操作,它只动主表,mysql.db、mysql.tables_priv、mysql.proxies_priv 里残留的权限记录全还在。MySQL 8.0+ 还有内存级权限缓存,删表后不 FLUSH PRIVILEGES 就连不上;即使 flush 了,也可能触发 ERROR 1396 (HY000),系统认为用户“还存在”,但查表又找不到。
DROP USER 是唯一能自动同步清理所有权限表的 DDL 操作,它会清掉:
– mysql.user
– mysql.db
– mysql.tables_priv
– mysql.columns_priv
– mysql.proxies_priv
– MySQL 8.0+ 的角色绑定关系(mysql.role_edges 中的 FROM_USER 条目)
不需要手动 FLUSH PRIVILEGES —— 但别忘了它不杀活连接。
必须先查清三类隐性依赖再执行 DROP USER
删完就断服务?大概率是没查这三处:
- 活跃连接:
SELECT ID, USER, HOST, COMMAND, TIME FROM information_schema.PROCESSLIST WHERE USER = 'xxx',有结果就得先KILL - 代理关系:
SELECT * FROM mysql.proxies_priv WHERE CONCAT(User, '@', Host) = 'xxx@%',如果其他账号靠它代理登录,删了 target 后 proxy 登录会静默失败 - 角色继承链:
SELECT FROM_USER, TO_USER FROM mysql.role_edges WHERE FROM_USER = 'xxx'(MySQL 8.0+),或WHERE TO_USER = 'xxx'(查谁继承了该账号的角色);5.7 及以前需先REVOKE role1 FROM 'xxx'@'%'
特别注意:MySQL 8.0.16+ 删除用户时会自动解除角色绑定,但不会删角色本身;5.7 完全不处理,留下孤儿角色。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
别漏掉 ''@'%' 和 IPv6 主机名
匿名用户是 User = ''(空字符串),不是 User IS NULL。漏判会导致严重安全隐患:
-
SELECT User, Host FROM mysql.user WHERE User = ''才是唯一正确查法 -
''@'%'允许任意远程 IP 免密登录,比''@'localhost'更危险 - MySQL 5.7+ 必须显式删
''@'::1'(IPv6 localhost),否则残留 - 5.6 或更早版本不能用
DROP USER ''@'host',得用DELETE FROM mysql.user WHERE User = ''+FLUSH PRIVILEGES
删完必须补一句:DELETE FROM mysql.db WHERE User = '' —— 因为 DROP USER 不动 mysql.db,而该表控制库级权限,残留条目可能让攻击者建 test 库甚至写 Webshell。
外部系统里的硬编码用户名常被忽略
DROP USER 只影响 MySQL 内部,以下地方不会自动失效,必须人工检查并同步修改:
- ProxySQL 的
mysql_users表 - JDBC URL 中的
user=xxx - 主从复制配置里的
SOURCE_USER - 应用连接池配置(如 HikariCP 的
spring.datasource.username) - 监控脚本、备份工具中硬编码的登录参数
验证是否真清干净:SELECT USER(), CURRENT_USER();,如果返回类似 ''@'localhost',说明要么没删净,要么缓存没刷——Docker / systemd 环境下 FLUSH PRIVILEGES 必须显式执行,不会自动重载。
真正麻烦的从来不是命令敲不对,而是删完才发现某个报警脚本、某台旧中间件、某条定时备份任务,还在用那个账号连着。

















