MySQL中“测试账号”需通过命名规范(如test_、tmp_前缀)、Host段(如'10.200.%')或外部标签识别,User@Host组合才是唯一标识;直接查mysql.user表须结合User与Host字段筛选,并注意角色授权、隐式权限及连接未失效等回收盲区。

先确认哪些账号属于“测试账号”
MySQL 不会自动标记“测试账号”,必须靠命名规范或元数据识别。常见做法是统一前缀(如 test_、tmp_)、固定主机段(如 '10.200.%')或在工单系统/配置库中打标签。直接查 mysql.user 表时,别只看 User 字段:Host 和 User 组合才是唯一标识。
推荐先执行这句筛选出疑似测试账号:
SELECT User, Host, account_locked, password_last_changed FROM mysql.user WHERE User LIKE 'test_%' OR User LIKE 'tmp_%' OR Host LIKE '10.200.%';
注意:如果账号是通过角色(role_edges)间接获得权限,仅查 user 表会漏掉真实权限来源。
批量执行 REVOKE 要绕开 ALL PRIVILEGES 的陷阱
REVOKE ALL PRIVILEGES ON *.* FROM ... 只撤显式授予的权限,但不会动 GRANT OPTION、不会清 mysql.user 里的管理字段(如 Super_priv),更不会解绑角色。生产环境里,一个 test_dev@'%' 账号可能因为绑了 dev_role,依然能执行 KILL 或 SHOW PROCESSLIST。
安全回收需三步并行:
- 逐个执行
REVOKE ALL PRIVILEGES, GRANT OPTION ON *.* FROM 'user'@'host'; - 对每个账号,运行
UPDATE mysql.user SET Super_priv='N', Reload_priv='N', Process_priv='N', Shutdown_priv='N' WHERE User='user' AND Host='host';,再跟FLUSH PRIVILEGES; - 查绑定角色:
SELECT FROM_USER, FROM_HOST FROM mysql.role_edges WHERE TO_USER='user' AND TO_HOST='host';,再对每个结果执行REVOKE 'role_name' FROM 'user'@'host';
别忘了空用户和隐式元数据权限
很多测试账号能查 information_schema 并不是你授的,而是 MySQL 8.0 默认给空用户 ''@'' 的隐式 SELECT 权限。这个权限不出现在 SHOW GRANTS 里,但真实生效——尤其当应用用错连接字符串导致匹配到空用户时,风险极大。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
必须补一刀:
REVOKE SELECT ON information_schema.* FROM ''@''; REVOKE SELECT ON performance_schema.* FROM ''@''; REVOKE SELECT ON sys.* FROM ''@'';
执行完记得验证:用目标测试账号登录,执行 SELECT COUNT(*) FROM information_schema.tables;,应报错 Access denied。
回收后最易被忽略的两点
第一,USAGE 权限无法撤销,所有用户默认拥有,它允许登录但不做任何事——所以 SHOW GRANTS 返回 GRANT USAGE ON *.* TO ... 是正常现象,不代表权限没清干净。
第二,已建立的连接不会立即失效。哪怕你把所有权限都撤光、FLUSH PRIVILEGES 也执行了,正在跑的连接仍持有旧权限。必须等连接断开重连,或主动 KILL 对应线程(查 SHOW PROCESSLIST 后手动终止)。这点在长连接场景(如 Java 应用未配置 idle timeout)下特别危险。










