最准最快的一线筛查方式是直接查mysql.user表的super_priv='y',但mysql 8.0+必须额外联查mysql.role_edges补角色继承链,否则会漏掉通过角色间接获得super权限的账号。

直接查 mysql.user 表的 Super_priv = 'Y' 是最准、最快的一线筛查方式,但 MySQL 8.0+ 必须额外补查角色继承链,否则一定漏人——尤其是那些没直连 'Y' 却能执行 KILL 或 SET GLOBAL 的账号。
查 mysql.user 表的 Super_priv 字段(所有版本都得做)
这个字段在 MySQL 5.7 及之前就是最终生效快照,不依赖角色、不走视图、不缓存中间态。查到就是真有。
- 必须用带
SELECT ON mysql.*权限的账号执行,比如root或拥有SYSTEM_USER角色的用户 -
Super_priv大小写敏感:写成super_priv或SUPER_PRIV会报错或返回空结果 - 刚执行过
GRANT SUPER ON *.* TO 'u'@'h'但没运行FLUSH PRIVILEGES,表里可能还是'N',而权限已实际生效——此时SHOW GRANTS才是真实依据 - 系统账户如
mysql.session、mysql.infoschema也显示Super_priv = 'Y',但它们不能登录,不算可被滥用的“真实”超级账号
MySQL 8.0+ 必须联查 mysql.role_edges 补角色继承路径
8.0 引入角色后,Super_priv = 'Y' 不再覆盖全部情况。用户可以没直连 'Y',却通过角色间接获得 SUPER。只查 mysql.user 会漏掉这类账号。
- 先查谁绑了角色:
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
SHOW GRANTS 永远不显示 SUPER,别信它
SHOW GRANTS FOR 'u'@'h' 输出里永远不会出现 SUPER 字样,哪怕用户真有该权限。这是 MySQL 内部设计限制,不是你查错了。
- 它只展示显式
GRANT语句,不解析角色继承、不读取mysql.user字段快照 - 没看到
GRANT SUPER ON *.* TO,不代表没权限——可能是角色继承,也可能是早期用INSERT INTO mysql.user直接改过字段 - 验证是否真能用:登录该账号后执行
KILL QUERY 1或SET GLOBAL max_connections = 1000,比看语句更直接
真正容易被忽略的是:删掉一个带 SUPER 的角色,并不会自动清理已通过该角色获得权限的用户字段——因为 Super_priv 在 mysql.user 行里是静态快照,不是实时计算的。回收时得显式执行 REVOKE SUPER ON *.* FROM 'u'@'h',而不是只删角色。











