最准最快方式是查mysql.user表super_priv='y',但mysql 8.0+必须额外联查role_edges并验证角色继承路径,否则漏检;super_priv大小写敏感且不自动刷新,show grants永不显示super关键字。

直接查 mysql.user 表的 Super_priv 字段是最准、最快的方式,但 MySQL 8.0+ 必须额外检查角色继承链,否则一定漏人。
查 mysql.user 表的 Super_priv = 'Y' 是基础动作
这个字段在 MySQL 5.7 及之前版本中就是最终答案:值为 'Y' 就真有 SUPER 权限,不依赖角色、不走视图、不缓存中间态。
- 执行语句:
SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y'; - 必须用有
SELECT ON mysql.*权限的账号(如root或带SYSTEM_USER角色的用户)执行 -
Super_priv大小写敏感:写成super_priv或SUPER_PRIV会查不到或报错 - 字段值不自动刷新:刚执行
GRANT SUPER ON *.* TO 'u'@'h'但没FLUSH PRIVILEGES,表里可能还是'N',而权限已生效——此时SHOW GRANTS才是真实依据
MySQL 8.0+ 必须连查 mysql.role_edges 补全角色路径
8.0 引入角色后,Super_priv = 'Y' 不再覆盖全部情况:用户可以没直连 'Y',却通过角色间接获得 SUPER。角色本身不能被显式授予 SUPER(GRANT SUPER ON *.* TO 'role'@'%' 会报错),但角色可被赋予含 SUPER 的权限组合(例如升级残留或手动改表),且用户激活后即生效。
- 先查谁绑了哪些角色:
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'; - 别信
IS_ROLE_GRANTED()或SHOW GRANTS FOR 'u'@'h' USING role:前者不反映 SUPER 实际生效状态,后者只在 8.0.22+ 支持且仍可能漏掉未激活角色
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;,比看语句更直接 - 系统保留账户如
mysql.session、mysql.infoschema在mysql.user中Super_priv = 'Y',但它们不可登录、无实际管理意义,别纳入审计范围
真正难的不是查到谁有 SUPER,而是确认这些账号是否还“需要”它——比如监控账号、备份工具用的账号,往往只需 REPLICATION SLAVE、PROCESS 等细粒度权限就够了。一旦开了 super_read_only = 0,拥有 SUPER 的账号就能绕过只读限制,这是线上从库误写事故最常见的根因。











