MySQL 8.0中CREATE ROLE前必须先启用角色支持,否则报ERROR 3719;需由高权限用户执行SET GLOBAL activate_all_roles_on_login = ON、GRANT ROLE_ADMIN、FLUSH PRIVILEGES,并写入my.cnf持久化,缺一不可。

CREATE ROLE 前必须先启用角色支持
直接执行 CREATE ROLE 'dev_role' 会报错 ERROR 3719 (HY000),不是语法错,而是功能被禁用。MySQL 8.0 默认关闭角色机制,必须由高权限用户(如 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 权限给角色 ≠ GRANT 角色给用户
这是最常混淆的点。角色是空壳,CREATE ROLE 只建元数据,不带任何权限。必须显式把权限授给角色本身:
- 正确:
GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'dev_role'@'%'; - 错误:
GRANT SELECT ON app_db.* TO 'dev1'@'%';(这是直接授给用户,绕过了角色) - 角色不支持列级权限:
GRANT SELECT(col1) ON t1 TO 'dev_role'直接报ERROR 1142 - 系统级权限(如
SHOW DATABASES)可授给角色,但加WITH GRANT OPTION会失败
赋权后建议立即执行 FLUSH PRIVILEGES,避免新用户无法继承变更。
角色名和 host 必须显式声明且保持一致
省略 host(如写成 'dev_role')等价于 'dev_role'@'%',但后续分配时若用户 host 不匹配,就会静默失败或报 ERROR 3530:
- 创建角色时推荐明确 host:
CREATE ROLE 'dev_role'@'%'; - 给角色赋权时 host 必须一致:
GRANT ... TO 'dev_role'@'%'; - 批量授角色给用户时,host 必须完全相同:
GRANT 'dev_role'@'%' TO 'u1'@'192.168.50.%', 'u2'@'192.168.50.%'; - 含特殊字符的角色名(如
ci-pipeline)必须用反引号:GRANT SELECT ON logs.* TO `ci-pipeline`;
host 不统一,SET DEFAULT ROLE ALL TO 会因匹配失败而中断,且无明确提示。
权限不会自动生效,SET DEFAULT ROLE 是硬性前提
只执行 GRANT 'dev_role'@'%' TO 'u1'@'%',用户登录后 CURRENT_ROLE() 仍是 NULL,所有权限不可用。必须由有 APPLICATION_PASSWORD_ADMIN 或 SYSTEM_VARIABLES_ADMIN 权限的管理员执行激活:
- 激活单个角色:
SET DEFAULT ROLE 'dev_role'@'%' TO 'u1'@'%'; - 批量激活全部已授角色:
SET DEFAULT ROLE ALL TO 'u1'@'%', 'u2'@'%'; - 若某用户未被授予任何角色,
SET DEFAULT ROLE ALL TO会报ERROR 3530 -
SHOW GRANTS FOR 'u1'@'%'永远只显示GRANT 'dev_role'@'%' TO ...,不会展开角色内权限——这不是配错了,是 MySQL 的设计行为
真正容易被忽略的是:角色权限链是“创建 → 授权 → 分配 → 激活”四步闭环,漏掉任意一环,CURRENT_ROLE() 就为空,且没有任何运行时报错提示。


















