set default role必须在grant之后执行,否则报error 3530;需确保to_user和to_host完全匹配,且activate_all_roles_on_login=off、mandatory_roles未配置,设置仅对新连接生效。

SET DEFAULT ROLE 必须在 GRANT 之后执行,否则一定报 ERROR 3530
错误不是语法或权限问题,而是 mysql.role_edges 表里根本没那条记录。MySQL 检查默认角色时,会严格比对 to_user 和 to_host 字段——哪怕你执行过 GRANT 'r_ro' TO 'app'@'%',但用户实际用 'app'@'localhost' 登录,就查不到匹配项。
先确认角色是否真授给了目标用户:SELECT * FROM mysql.role_edges WHERE to_user = 'app' AND to_host = 'localhost';,无结果就得重做 GRANT。
- host 必须完全一致:用户是
'app'@'127.0.0.1',就不能用'app'@'%'去设默认角色 - 角色名大小写敏感:若
lower_case_table_names=0,'R_RO'和'r_ro'是两个角色,GRANT和SET DEFAULT ROLE必须用同一拼写 -
FLUSH PRIVILEGES在 8.0+ 通常不需要,别靠它“碰运气”
activate_all_roles_on_login=ON 会让 SET DEFAULT ROLE 彻底失效
一旦全局启用 activate_all_roles_on_login=ON,所有已授予的角色都会在登录时自动激活,SET DEFAULT ROLE 设置的“最小权限集”会被静默覆盖。
如果你依赖 SET DEFAULT ROLE 'r_ro' TO 'app'@'%' 控制权限边界,就必须保持该变量为 OFF(即默认值)。
-
SET GLOBAL activate_all_roles_on_login = ON只影响新连接,重启后恢复默认,必须写进my.cnf的[mysqld]段落才持久 - 误设为 ON 后再执行
SET DEFAULT ROLE不报错,但CURRENT_ROLE()查不到变化,权限实际由全部已授角色叠加决定 - 验证是否生效:
SELECT @@activate_all_roles_on_login;返回1才算成功
默认角色只对后续新连接生效,当前会话不刷新
SET DEFAULT ROLE 是持久化配置,不是即时刷新命令。它写入系统表,但只影响用户下次新建连接时的角色激活状态。
别在当前连接里查 CURRENT_ROLE() 验证——那只是旧会话状态。必须新开一个连接,再执行:
SELECT CURRENT_ROLE();——应返回你设的角色名,如 'r_ro',不是 NULL 或空字符串。
- 想清空默认角色:
SET DEFAULT ROLE NONE TO 'app'@'%'; - 设多个默认角色:
SET DEFAULT ROLE 'r1', 'r2' TO 'app'@'%';,权限叠加;但只要其中一个被REVOKE,它就自动从默认列表剔除 - 用户账户不能被锁定:
SELECT account_locked FROM mysql.user WHERE user = 'app' AND host = '%';返回必须是N - 密码不能过期:
SELECT password_expired FROM mysql.user WHERE user = 'app' AND host = '%';同样得是N
mandatory_roles 会静默覆盖 DEFAULT ROLE
如果实例配置了 mandatory_roles,比如 SET PERSIST mandatory_roles = "'dba_role'@'localhost'";,那么无论你如何设置 SET DEFAULT ROLE,该强制角色都会在每次登录时自动激活,并覆盖所有默认行为。
这不是 bug,是设计逻辑:强制角色无法被单个用户 REVOKE,也不能 DROP ROLE,除非先清空 mandatory_roles 并重启服务(或动态重载)。
- 强制角色适合极少数场景:全库只读兜底、审计日志权限保障
- 误配后恢复麻烦,务必提前确认是否真需要
- 检查当前强制角色:
SELECT @@mandatory_roles;
最常被卡住的点,其实是第一步:角色还没真正授给用户,就急着设默认角色。顺序反了、host 错了、大小写混了,整套机制就停在 ERROR 3530。











