MySQL 8.0 的角色是独立权限容器,非用户组语法糖;必须三步完成:CREATE ROLE → GRANT 权限 TO 角色 → GRANT 角色 TO 用户,且需激活(SET ROLE 或设默认角色)才生效。

MySQL 8.0 的角色(ROLE)不是“用户组”的语法糖,而是独立的权限容器——直接 CREATE ROLE 后不赋权、不激活,它对任何用户都无效。
CREATE ROLE 之后必须显式授权才能生效
角色创建后是空壳,不自动继承任何权限,也不自动绑定到用户。常见错误是以为建完角色就“可用”了:
- 执行
CREATE ROLE 'app_reader';后立即用SET ROLE 'app_reader';,会报错ERROR 3530 (HY000): Access denied for user ... to set role 'app_reader' - 原因:该角色尚未被授予任何权限,且当前用户没有
ROLE_ADMIN权限来切换角色 - 必须分三步走:
CREATE ROLE→GRANT ... ON ... TO 'role_name'→GRANT 'role_name' TO 'user_name'@'host' - 注意第二步的
GRANT对象是角色名(带引号),不是用户名;第三步才是把角色分配给具体用户
SET ROLE 需要用户有 ROLE_ADMIN 或被显式允许
普通用户默认不能随意切换角色,即使已被授予权限。激活角色有两种方式:
- 管理员执行:
SET DEFAULT ROLE 'app_reader' TO 'alice'@'localhost';—— 这样 alice 登录后自动激活该角色 - 用户自己执行:
SET ROLE 'app_reader';,但前提是其账户拥有ROLE_ADMIN权限,或管理员已通过GRANT PROXY ON 'app_reader' TO 'alice'@'localhost';显式放行 - 若未设默认角色,又没开
ROLE_ADMIN,用户登录后仍处于“无激活角色”状态,所有角色权限不可见
权限回收时 GRANT OPTION 和 WITH ADMIN OPTION 容易混淆
角色权限的传递性由两个不同选项控制,混用会导致权限残留:
-
GRANT SELECT ON app.* TO 'app_reader' WITH ADMIN OPTION;:允许该角色把「角色本身」再授予其他用户(即管理角色归属) -
GRANT SELECT ON app.* TO 'app_reader' WITH GRANT OPTION;:允许该角色把「SELECT 权限」再授予其他用户(MySQL 8.0 中WITH GRANT OPTION对角色无效,会报错ERROR 3529 (HY000): Cannot grant the specified privilege to a role) - 所以给角色赋权时,只用
WITH ADMIN OPTION控制角色分发权;权限本身的再授权只能由具有GRANT OPTION的用户(非角色)完成
SHOW GRANTS 输出里角色权限藏得比较深
查用户权限时,SHOW GRANTS FOR 'alice'@'localhost'; 默认只显示直授权限,不展开角色内容。要看到完整视图:
- 先确认用户是否绑定了角色:
SELECT * FROM mysql.role_edges WHERE TO_HOST = 'localhost' AND TO_USER = 'alice'; - 查看某角色的权限:
SHOW GRANTS FOR 'app_reader'; - 查看用户当前激活的角色(需已登录并执行过
SET ROLE):SELECT CURRENT_ROLE(); - 注意:
SHOW GRANTS对角色的输出格式是GRANT ... TO 'role_name'@'%',这里的@'%'是占位符,不代表真实 host —— 角色本身无 host 概念
角色权限真正起效的前提是:角色被授予权限 + 被分配给用户 + 用户已激活(或设为默认)。漏掉任一环,SELECT 就会报 ERROR 1142 (42000): SELECT command denied —— 这时候别急着加权限,先用 CURRENT_ROLE() 确认角色是不是真在运行。











