create role本身不授予权限且不自动生效,必须依次启用activate_all_roles_on_login、创建角色、grant授权给角色、grant角色给用户、set default role激活,缺一不可;否则current_role()返回null,权限不生效。

CREATE ROLE 本身不授予权限,也不自动生效;必须配合 GRANT、SET DEFAULT ROLE 和全局变量 activate_all_roles_on_login 才能真正用起来。
CREATE ROLE 前必须启用角色支持
MySQL 8.0 默认关闭角色功能,CREATE ROLE 语句即使语法正确,执行也会报错:ERROR 3719 (HY000): 'role_admin'@'%' is not set as a role 或直接提示权限不足。根本原因是:
-
activate_all_roles_on_login全局变量默认为OFF - 当前用户未被授予
ROLE_ADMIN权限
必须由高权限用户(如 root)先执行:
SET GLOBAL activate_all_roles_on_login = ON; GRANT ROLE_ADMIN ON *.* TO 'admin_user'@'%'; FLUSH PRIVILEGES;
⚠️ 注意:activate_all_roles_on_login 是动态变量,MySQL 重启后失效,生产环境务必写入 my.cnf:
[mysqld] activate_all_roles_on_login=ON
GRANT 权限给角色,不是给用户
角色是“权限容器”,创建后为空。给角色授权的语法和给用户一样,但目标必须是角色名(带 host 段),例如:
GRANT SELECT, INSERT ON myapp.* TO 'app_writer'@'%';
常见错误包括:
- 漏写 host 段(如写成
'app_writer'而非'app_writer'@'%'),导致GRANT报错ERROR 3530 (HY000) - 误对用户执行
GRANT SELECT ON myapp.* TO 'app_writer'@'%'—— 这是在试图给一个不存在的用户授权,而非给角色 - 尝试授予列级权限(如
GRANT SELECT(col1)),会直接报错,角色不支持列级授权
系统级权限(如 CREATE USER)可授给角色,但不能加 WITH GRANT OPTION,否则失败。
角色要生效,必须 SET DEFAULT ROLE 绑定到用户
角色创建并授权后,还不能用。必须走完最后两步:
-
GRANT 'app_writer'@'%' TO 'webuser'@'%':建立角色与用户的绑定关系(只是关联,不激活) -
SET DEFAULT ROLE 'app_writer'@'%' TO 'webuser'@'%':指定该角色为用户登录时默认激活的角色
缺了 SET DEFAULT ROLE,用户登录后 CURRENT_ROLE() 返回 NULL,所有权限均不可见、不可用。这也是最容易被忽略的一环。
如果用户已有多个角色,可以用逗号分隔一次性设置:
SET DEFAULT ROLE 'app_reader'@'%', 'app_writer'@'%' TO 'webuser'@'%';
验证角色是否生效的最小检查链
执行完全部操作后,用目标用户登录,运行以下语句确认闭环完整:
-
SELECT CURRENT_ROLE();—— 应返回已设置的默认角色名(如'app_writer'@'%') -
SHOW GRANTS;—— 应列出该角色所拥有的全部权限,而不是空或仅显示USAGE - 实际执行一条受控操作(如
SELECT * FROM myapp.users LIMIT 1;)—— 验证权限真实可用
任何一环失败,都说明前面某步遗漏或 host 匹配不一致(比如角色建在 '%',却试图授给 'webuser'@'localhost')。











