MySQL 8.0+ 仅查 mysql.user.Super_priv 会漏掉角色继承的 SUPER 权限,必须结合 mysql.role_edges、SHOW GRANTS FOR role 和用户绑定关系三步验证,且需 SET ROLE 激活;SHOW GRANTS 不显示 SUPER,实际权限须通过 KILL QUERY 或 SET GLOBAL 验证。

直接查 mysql.user 表的 Super_priv 字段会漏人
MySQL 5.7 及更早版本中,SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y' 是准确的,但 MySQL 8.0+ 引入角色后,这个查询会漏掉大量真实拥有 SUPER 权限的账号——因为角色继承来的权限在 mysql.user 表里仍显示为 'N'。你看到的 'N' 不代表没权限,只是没直授。
SHOW GRANTS FOR 'u'@'h' 永远不显示 SUPER
这是 MySQL 的设计限制,不是你操作错了。SHOW GRANTS 只输出显式执行过的 GRANT 语句,完全忽略角色链、忽略 INSERT INTO mysql.user 直接改字段等非标准授权方式。所以:
- 没看到
GRANT SUPER ON *.* TO≠ 没有 SUPER 权限 - 看到
GRANT ALL PRIVILEGES ON *.* TO也不等于有 SUPER(ALL 不包含 SUPER) - 真正验证方法只有登录后执行
KILL QUERY 1或SET GLOBAL max_connections = 100—— 成功了就是有
必须连查 mysql.role_edges 才能覆盖 8.0+ 角色继承场景
分三步走,缺一不可:
- 先查谁绑了角色:
SELECT FROM_USER, FROM_HOST, TO_ROLE FROM mysql.role_edges; - 对每个
TO_ROLE,运行SHOW GRANTS FOR 'role_name'@'%'(注意主机名不能省,否则报错);若输出含GRANT SUPER ON *.* TO,说明该角色带 SUPER - 再反查哪些用户被授了这个角色:
SELECT User, Host FROM mysql.user u JOIN mysql.role_edges r ON u.User = r.FROM_USER AND u.Host = r.FROM_HOST WHERE r.TO_ROLE = 'xxx';
注意:用户必须已执行过 SET ROLE 'xxx',权限才激活;否则即使查到角色链,当前会话也无 SUPER。
高风险非管理账号的判定逻辑不能只看权限字段
单纯筛选 Super_priv = 'Y' 会把 mysql.session、mysql.infoschema 这类系统账户也拉进来,它们不能登录,不算真实风险点。真正要揪的是:
- Host 为
'%'或网段宽泛(如'10.%.%.%')的账号 - 用户名明显非 DBA 习惯命名(如
'app_report'、'sync_user') - 同时具备
Grant_priv = 'Y'或Repl_slave_priv = 'Y'的组合 - 密码未定期更换、account_locked = 'N' 且长期无登录记录(需结合
performance_schema或日志交叉判断)
最易被忽略的是:刚执行 GRANT SUPER ON *.* TO 'u'@'h' 但没运行 FLUSH PRIVILEGES,此时 mysql.user 表仍是 'N',而权限已生效——SHOW GRANTS 也看不到,只能靠实际操作验证。


















