show grants 输出含 using 表示权限来自角色继承,否则为直接授予;需结合 mysql.role_edges 和 mysql.default_roles 确认角色绑定与默认激活状态,并以 current_user() 为准查权限源头。

SHOW GRANTS 输出里有 USING 就是角色权限
MySQL 8.0+ 启用角色机制后,权限可能来自直接授予用户,也可能来自角色继承。最直接的判断方式就是看 SHOW GRANTS 的输出是否含 USING 子句。
例如:
GRANT SELECT ON `sales`.* TO 'reporter'@'%' USING 'readonly_role';
这行就明确表示 SELECT 权限不是直接给 'reporter'@'%' 的,而是通过角色 'readonly_role' 继承来的。
- 没出现
USING:权限是显式授予该用户的(比如GRANT INSERT ON mydb.t1 TO 'u'@'h';) - 出现
USING 'role_name':权限来自该角色,需进一步查mysql.role_edges确认绑定关系 - 同一用户可能混用两种来源,
SHOW GRANTS会把所有显式授予 + 所有角色继承的权限都列出来,但不标注哪条来自哪个角色
查 mysql.role_edges 确认角色绑定关系
仅靠 SHOW GRANTS 不知道某个角色是否被激活、是否设为默认角色。得查 mysql.role_edges 和 mysql.default_roles。
确认用户是否被授予某角色:
SELECT FROM_HOST, FROM_USER, TO_HOST, TO_USER, ROLE_NAME FROM mysql.role_edges WHERE TO_USER = 'reporter' AND TO_HOST = '%';
结果里每行代表一次角色授予动作。注意:FROM_USER 是授予权限的管理员账号,TO_USER 才是目标用户。
- 如果查不到记录,说明该用户没被显式赋予任何角色(哪怕
SHOW GRANTS显示了USING,也可能是旧缓存或代理用户干扰) -
mysql.default_roles表决定哪些角色在登录时自动激活;若某角色没出现在这里,即使被授予,也不会生效,除非手动SET ROLE - 执行完角色操作后,必须
FLUSH PRIVILEGES或重启连接,否则role_edges变更可能不立即反映在SHOW GRANTS中
CURRENT_USER() 和 USER() 不一致时权限来源更复杂
权限实际生效的是 CURRENT_USER() 返回的账户,不是你登录时声明的 USER()。如果两者不同,说明用了代理用户(PROXY)或匿名匹配,权限可能来自被代理的账户或其角色。
- 运行
SELECT USER(), CURRENT_USER();—— 若返回'proxy_user'@'%'和'real_user'@'localhost',那真正起作用的是后者及其角色 - 此时
SHOW GRANTS FOR CURRENT_USER()查的是real_user的权限,但mysql.role_edges要查的也是real_user,不是proxy_user - 代理用户本身可以拥有自己的角色,但只有当它被设为
WITH ADMIN OPTION并显式SET ROLE时才生效,日常极少这么用
为什么不能只查 mysql.user 表判断权限来源
mysql.user 表只存全局权限和账户元数据(如 account_locked),完全不记录角色信息,也不体现数据库/表级权限是否来自角色。
- 字段如
Select_priv='Y'在 8.0+ 已弃用,即使值为 Y,也不代表用户真有 SELECT 权限——可能已被角色覆盖或禁用 -
mysql.user里没有role相关字段,查它等于忽略整个角色体系 - 想定位权限源头,必须组合三处:
SHOW GRANTS(最终效果)、mysql.role_edges(谁给了谁什么角色)、mysql.default_roles(哪些角色默认激活)
角色权限的链路比直觉中更绕:授角色、设默认、登录激活、会话切换,任意一环断掉都会让 USING 不生效。别只盯着一条命令输出,得顺着 CURRENT_USER() 往下挖。











