MySQL 8.0 的角色(
ROLE)不是“锦上添花”,而是解决权限管理混乱的刚需工具——只要你有 3 个以上需要同类权限的用户,或频繁调整权限,就该用
ROLE,否则迟早会
GRANT错、
REVOKE漏、审计时抓瞎。
创建和授权角色:别跳过主机名,否则登录就失效
角色名其实是个“伪用户”,格式是
'role_name'@'host',省略
@'host'默认为
@'%'。但问题来了:如果你创建的是
CREATE ROLE 'dev';(即
@'%'),而用户是
'alice'@'localhost',后续
GRANT 'dev' TO 'alice'@'localhost';虽然语法通过,但激活时可能因上下文 host 匹配逻辑出问题(尤其在 strict SQL mode 下)。 推荐显式声明 host,保持一致性:比如开发角色统一用
@'%',DBA 角色用
@'localhost'给角色授予权限,和给用户一样,但对象是角色名:
GRANT SELECT, INSERT ON app_db.* TO 'dev_role'@'%';注意:角色本身不能登录,所以不需要
IDENTIFIED BY,也不支持密码策略
分配角色给用户后,为什么还是没权限?
这是最常踩的坑:角色授给了用户,
SHOW GRANTS FOR 'user'@'host';也显示成功,但一执行
SELECT就报
ERROR 1045 (28000): Access denied——根本原因是角色默认不激活。 必须显式激活才能生效,方式有两种:
– 当前会话临时激活:
SET ROLE 'dev_role'@'%';
– 设为登录默认激活(推荐生产环境):
SET DEFAULT ROLE 'dev_role'@'%' TO 'alice'@'localhost';如果想让所有已分配角色自动激活,启用系统变量:
SET PERSIST activate_all_roles_on_login = ON;(需
SYSTEM_VARIABLES_ADMIN权限) 检查当前生效角色:
SELECT CURRENT_ROLE();返回
NULL就说明没激活
强制角色(mandatory_roles
):方便但不可逆,慎用
设为强制的角色,所有用户(包括未来新建的)都会隐式拥有它,连
REVOKE都删不掉权限——这不是“快捷方式”,而是“全局锁”。 配置方式(需
ROLE_ADMIN或
SUPER权限):
SET PERSIST mandatory_roles = "'dba_role'@'localhost','read_only'@'%';"一旦写入,该角色的权限无法被单个用户撤销,也不能
DROP ROLE,除非先清空
mandatory_roles典型适用场景只有两个:全库只读兜底(如灾备从库)、审计日志角色(确保所有连接都带 trace 权限) 误配后恢复麻烦:必须用
SET PERSIST mandatory_roles = '';再重启服务(或动态重载,取决于版本)
查看与调试:别只信 SHOW GRANTS
SHOW GRANTS FOR 'user'@'host'只告诉你“这个用户被授予了哪些角色”,但不告诉你“这些角色具体有哪些权限”。你看到
GRANT 'dev_role'@'%' TO 'alice'@'localhost',却不知道
dev_role到底有没有
DELETE权限。 查角色本身权限:
SHOW GRANTS FOR 'dev_role'@'%';查用户实际生效权限(含角色继承):
SHOW GRANTS FOR 'alice'@'localhost' USING 'dev_role'@'%';查当前会话权限快照(含动态激活状态):
SELECT * FROM INFORMATION_SCHEMA.ROLE_TABLE_GRANTS WHERE ROLE_NAME = 'dev_role';
真正难的不是语法,而是权限叠加逻辑:多个角色 + 强制角色 + 显式用户权限,最终生效的是并集,但拒绝权限(
REVOKE)只作用于直接授予项,不会穿透角色——这点在排查越权或失权时最容易误判。
