MySQL 8.0角色权限生效必须完成创建→授权→绑定→激活四步闭环;缺一即报ERROR 1045;需先启用角色支持、授ROLE_ADMIN、持久化配置、显式SET DEFAULT ROLE且查权限时须用USING子句。

MySQL 8.0 的角色权限管理不是“开了就能用”,而是必须走完创建 → 授权 → 绑定 → 激活四步闭环,缺一不可;跳过任意一步,SELECT 都会报 ERROR 1045 (28000): Access denied。
CREATE ROLE 前必须先启用角色支持
直接执行 CREATE ROLE 'app_reader'; 很可能报错:ERROR 3719 (HY000): 'role_admin'@'%' is not set as a role.。这不是语法问题,是 MySQL 8.0 默认禁用角色功能。
- 由 root 或高权限用户执行:
SET GLOBAL activate_all_roles_on_login = ON; - 授予
ROLE_ADMIN权限:GRANT ROLE_ADMIN ON *.* TO 'admin_user'@'%'; - 执行
FLUSH PRIVILEGES;确保生效 - 为防服务重启失效,需在
my.cnf中持久化:[mysqld]\nactivate_all_roles_on_login=ON
GRANT 权限给角色 ≠ 用户能用,必须再 GRANT 角色给用户
很多人以为 GRANT SELECT ON app.* TO 'reader_role'; 后,只要把用户加进这个角色就完事了——其实这只是第一步。角色本身不登录、不连接,它只是个空容器。
- 角色名必须带主机名(推荐统一用
@'%'):CREATE ROLE 'reader_role'@'%'; - 给角色授具体权限(注意:不支持列级授权,
GRANT SELECT(col1)会报错):GRANT SELECT ON app.* TO 'reader_role'@'%'; - 再把角色绑给用户:
GRANT 'reader_role'@'%' TO 'api_user'@'%'; - 此时
SHOW GRANTS FOR 'api_user'@'%';仍看不到角色权限——这是正常现象
SET DEFAULT ROLE 是权限生效的临门一脚
没执行 SET DEFAULT ROLE,用户连上就是“裸权限”状态:CURRENT_ROLE() 返回 NONE,SELECT 直接被拒。
- 激活单个角色:
SET DEFAULT ROLE 'reader_role'@'%' TO 'api_user'@'%'; - 激活所有已授予角色(慎用):
SET DEFAULT ROLE ALL TO 'api_user'@'%'; - 该语句需由有
APPLICATION_PASSWORD_ADMIN或SYSTEM_VARIABLES_ADMIN权限的管理员执行,普通用户无法自设 - 若应用连接池未自动执行该语句,就得在每次连接后手动
SET ROLE 'reader_role';
查权限时容易漏掉 USING 子句
SHOW GRANTS FOR 'user'@'host'; 只显示直接授予用户的权限,角色继承的权限默认不展开——这导致大量误判:“明明配了,怎么没效果?”
- 查某角色带来的实际权限:
SHOW GRANTS FOR 'api_user'@'%' USING 'reader_role'@'%'; - 查用户被授予了哪些角色:
SELECT * FROM mysql.role_edges WHERE to_user = 'api_user' AND to_host = '%'; - 查当前会话激活的角色:
SELECT CURRENT_ROLE();—— 返回NONE就说明根本没激活 - 验证连接是否加载角色:旧客户端可能因认证插件不匹配导致角色不加载,建议显式指定
--default-auth=mysql_native_password
真正卡住人的从来不是命令记不住,而是流程断在中间某环:比如忘了 FLUSH PRIVILEGES,或用了 'reader_role' 却没写 @'%' 导致 host 匹配失败,又或者查权限时漏了 USING——这些细节不逐条对齐,GRANT 写得再全也白搭。


















