应查information_schema.enabled_roles视图确认当前会话已激活的角色,因show grants不反映动态权限实际启用状态;动态权限需角色激活或直接授予current_user后才生效,且受set role控制。

查当前会话的动态权限用 SHOW GRANTS 不够准
MySQL 8.0 的动态权限(如 BACKUP_ADMIN、CONNECTION_ADMIN)和传统静态权限不同:它们不绑定到用户账户的全局/库/表级授权记录里,而是通过 GRANT 直接赋予会话或用户,并可能被 SET PERSIST 或运行时 SET ROLE 影响。单纯执行 SHOW GRANTS 只显示静态权限 + 显式授予的动态权限,但**不会反映当前会话实际启用的状态**——比如你 GRANT 了某个动态权限,但没 SET ROLE 激活,它就不生效。
真正生效的动态权限得查 INFORMATION_SCHEMA.APPLICABLE_ROLES 和 ROLE_TABLES
MySQL 8.0 提供了两个关键视图来判断“当前会话正在用哪些动态权限”:
-
INFORMATION_SCHEMA.APPLICABLE_ROLES列出当前会话**可访问的所有角色**(包括默认激活的和手动SET ROLE过的) -
INFORMATION_SCHEMA.ROLE_TABLES(更准确地说是INFORMATION_SCHEMA.ROLE_ROUTINE_GRANTS或直接查mysql.role_edges)不是标准接口;实际应结合SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES—— 这才是 MySQL 8.0.19+ 正确反映**当前已启用角色**的视图
所以最直接的方式是:
SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
该结果中每一行代表一个当前会话已激活的角色;而动态权限正是通过角色授予的(或直接 GRANT ... TO CURRENT_USER 后自动生效)。如果你没用角色,而是直接 GRANT BACKUP_ADMIN ON *.* TO 'u'@'%'; 并且该用户已连接,那这个权限就属于 CURRENT_USER 的隐式上下文,此时需额外确认:
- 是否执行过
SET ROLE NONE?—— 会清空所有角色权限,包括直接授予的动态权限 - 是否在存储过程或函数内调用?—— 动态权限默认不跨上下文继承,除非显式声明
SQL SECURITY DEFINER并确保 definer 拥有该权限
快速验证某动态权限是否真在起作用
光看角色列表还不够,得测试权限是否能触发对应操作。例如检查 GROUP_REPLICATION_ADMIN 是否生效:
- 执行
SELECT group_replication_get_communication_protocol();—— 若报错ERROR 3037 (HY000): Access denied; you need (at least one of) the GROUP_REPLICATION_ADMIN privilege(s) for this operation,说明权限未启用 - 执行
SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;空结果?那就得查SELECT CURRENT_USER(), USER();确认连接身份,再查SELECT * FROM mysql.role_edges WHERE TO_HOST = '%' AND TO_USER = 'your_user'; - 注意:某些动态权限(如
SYSTEM_VARIABLES_ADMIN)影响的是能否执行SET PERSIST,不是 SELECT 类操作,必须针对具体命令测
容易漏掉的边界情况
动态权限的“生效”不是布尔开关,它依赖三层叠加:
- 是否已被
GRANT给当前用户(或其所属角色) - 该用户是否在当前会话中通过
SET ROLE显式启用了对应角色(或默认角色已配置) - 是否被
SET ROLE NONE或会话重连后未重新SET ROLE而中断
尤其是应用使用连接池时,连接复用可能导致角色状态残留或丢失——这时候查 INFORMATION_SCHEMA.ENABLED_ROLES 返回空,不代表权限没授,只代表当前会话没激活。











