SET DEFAULT ROLE生效需满足四前提:角色已显式授予且host精确匹配、用户账户未锁定或过期、activate_all_roles_on_login已全局开启、由高权限用户执行;否则报ERROR 3530。

SET DEFAULT ROLE 执行前必须确认角色已正确授予
执行 SET DEFAULT ROLE 不会自动补全授权关系,它只激活已存在的绑定。如果 SELECT * FROM mysql.role_edges WHERE TO_USER = 'user1' AND TO_HOST = '%' 查不到记录,SET DEFAULT ROLE 'app_reader' TO 'user1'@'%' 会报 ERROR 3530。
常见疏漏点:
- GRANT 角色时 host 不匹配:比如角色是
'app_reader'@'%',却对'user1'@'localhost'授予,后续对同一用户设默认角色必须用'user1'@'localhost',不能混用 - 角色名含特殊字符(如
-或.)未加反引号:GRANT `ci-pipeline` TO 'user1'@'%'才合法,否则语法错误 - 用户账户被锁或密码过期:
account_locked = 'Y'或password_expired = 'Y'会导致 SET DEFAULT ROLE 失败,即使权限足够
activate_all_roles_on_login 必须全局开启,否则角色不加载
MySQL 8.0 默认关闭角色支持,CREATE ROLE 可能静默失败或报 ERROR 3719。不启用该变量,用户登录后 CURRENT_ROLE() 永远返回 NONE,哪怕已设默认角色。
操作要点:
- 由 root 或高权限用户执行:
SET GLOBAL activate_all_roles_on_login = ON - 生产环境必须写入配置文件:
activate_all_roles_on_login=ON加到my.cnf的[mysqld]段下,否则重启失效 - 配套授予
ROLE_ADMIN权限:GRANT ROLE_ADMIN ON *.* TO 'admin_user'@'%',否则普通管理员无法管理角色
连接池场景下默认角色不自动生效
HikariCP、Druid 等主流连接池获取连接时不会执行任何会话级初始化语句,即使你已成功执行 SET DEFAULT ROLE,新连接的 CURRENT_ROLE() 仍为 NONE。
解决方案分两类:
- JDBC URL 中添加参数:
sessionVariables=default_role=app_reader@% - 连接池配置
connection-init-sql:SET DEFAULT ROLE 'app_reader'@'%' - 注意:若角色名含
@,URL 参数中需 URL 编码;而connection-init-sql写法更直观、不易出错
验证是否真正生效,别信 SHOW GRANTS 输出
SHOW GRANTS FOR 'user1'@'%' 只显示直授权限和角色绑定语句,完全不展开角色所含权限——这是 MySQL 的设计行为,不是配置失败。
真验证要三步走:
- 查当前会话角色:
SELECT CURRENT_ROLE();—— 返回非NONE值才算激活 - 查该角色赋予用户的实际权限:
SHOW GRANTS FOR 'user1'@'%' USING 'app_reader'@'%' - 真跑一条受控 SQL:
SELECT COUNT(*) FROM myapp.orders;—— 看是否报 Access denied
最易忽略的是连接池初始化和 host 匹配精度,这两处出问题时,所有上层配置看起来都“对”,但权限就是不生效。


















