mandatory_roles是MySQL 8.0唯一强制角色机制,所有新连接用户(含root)自动激活且不可撤销;需SET PERSIST配置、带主机名与正确引号格式,仅对新连接生效,验证须用CURRENT_ROLE()而非SHOW GRANTS。

MySQL 8.0 的“强制访问控制”不是操作系统级的 MAC(如 SELinux),而是通过 mandatory_roles 配置实现的**全局角色强制绑定**——所有新连接用户(包括 root)都会自动获得指定角色权限,且无法被撤销。这确实是 MySQL 唯一接近“强制”的 RBAC 控制手段,但必须手动启用且极易误配。
mandatory_roles 是什么,为什么它算“强制”?
mandatory_roles 是一个系统变量(支持 SET PERSIST),一旦设置,所有后续新建连接(无论用户是谁、用什么账号登录)都会隐式激活该角色,且这个激活行为不可被 REVOKE、DROP ROLE 或 SET ROLE NONE 取消。
- 它不写入
mysql.role_edges,也不出现在SHOW GRANTS FOR user中,只在CURRENT_ROLE()返回值里可见 - 即使你执行
REVOKE 'auditor' FROM 'dev_user'@'%',下次dev_user登录后仍会拥有auditor权限 - 连
root登录也会带上它——这点常被忽略,导致安全审计时漏掉高危隐性权限
如何正确设置 mandatory_roles?
必须用 SET PERSIST(或直接写入配置文件),仅 SET GLOBAL 不持久,重启即失效:
SET PERSIST mandatory_roles = '''auditor''@''%''';
- 角色名必须带主机名,且用单引号包裹整个字符串;内部再套一层单引号转义(即
'auditor'@'%'要写成'''auditor''@''%''') - 不能写成
SET PERSIST mandatory_roles = 'auditor',否则报错ERROR 3529 (HY000) - 配置生效后,已有连接不受影响——只对新连接起作用,这点调试时容易误判“没生效”
怎么验证 mandatory_roles 是否生效?
别查 SHOW GRANTS,它完全不显示 mandatory role:
- 新开一个连接(比如
mysql -u dev_user -p),立即执行:SELECT CURRENT_ROLE();—— 若返回'auditor'@'%',说明已强制激活 - 执行一条受该角色控制的操作,例如
SELECT * FROM mysql.general_log;(假设auditor有此权限),成功即确认权限已注入 - 想清空?只能用:
SET PERSIST mandatory_roles = '';,没有其他绕过方式
mandatory_roles 和 DEFAULT ROLE 冲突吗?
不冲突,但优先级更高:如果用户同时设置了 DEFAULT ROLE 'app_reader',又启用了 mandatory_roles = 'auditor',那么 CURRENT_ROLE() 会返回 'app_reader','auditor'(逗号分隔的元组)。但注意:
-
mandatory_roles无法被SET ROLE切换掉,而DEFAULT ROLE可以被临时覆盖 - 若两个角色对同一张表有冲突权限(比如一个给
SELECT,另一个显式REVOKE SELECT),以最后加载的角色为准,顺序由mysql.role_edges插入时间决定,不可控 - 生产环境慎用多个 mandatory role,调试困难,审计链路断裂
真正麻烦的不是配置本身,而是 mandatory_roles 一旦设错,连 root 都无法在不重启或改配置的前提下解除——它像一个隐形权限钩子,静默附着在每个新会话上,直到你想起去查 CURRENT_ROLE() 并重置 mandatory_roles。











