MySQL 8.0+创建带角色用户必须完成五步闭环:CREATE ROLE建角色、GRANT授予权限给角色、CREATE USER建用户、GRANT将角色分配给用户、SET DEFAULT ROLE启用角色;缺任一环权限均不生效。

CREATE ROLE后必须先GRANT权限,否则角色是空的
角色创建后不带任何权限,哪怕叫admin_role,它也只是一个空容器。执行CREATE ROLE 'app_writer'只是在mysql.role_edges里写入一条元数据,没赋权就等于没配置。
-
GRANT SELECT, INSERT ON myapp.* TO 'app_writer'是对角色授权,不是对用户 - 角色不支持列级权限:
GRANT SELECT(col1)会报错 - 系统级权限可以授给角色,但不能加
WITH GRANT OPTION,否则报错 - 角色名含
-或.时,必须用反引号:比如GRANT SELECT ON logs.* TO `ci-pipeline`
GRANT角色给用户 ≠ 权限生效,必须SET DEFAULT ROLE
很多人执行了GRANT 'app_writer' TO 'dev1'@'%'就以为完事了,结果用户一连上去还是Access denied。这是因为GRANT role TO user只建立绑定关系,不激活权限。
- 必须显式执行
SET DEFAULT ROLE 'app_writer' TO 'dev1'@'%',后续所有新连接才会自动激活 - host必须精确匹配:如果角色是授给
'dev1'@'%',就不能对'dev1'@'localhost'设默认角色 - 一个用户可被授予多个角色,但
SET DEFAULT ROLE ALL TO要求该用户已在mysql.role_edges中存在对应记录,否则报ERROR 3530 - 普通用户无法执行
SET DEFAULT ROLE,需APPLICATION_PASSWORD_ADMIN或SYSTEM_VARIABLES_ADMIN权限
验证角色是否真生效,别只看SHOW GRANTS FOR
SHOW GRANTS FOR 'dev1'@'%'只会显示GRANT 'app_writer' TO ...这一行,不会展开角色内部的SELECT权限——这不是权限没配好,而是MySQL默认行为。
- 查角色带来的真实权限,必须加
USING子句:SHOW GRANTS FOR 'dev1'@'%' USING 'app_writer' - 确认角色是否已激活:
SELECT CURRENT_ROLE(),返回NULL说明根本没激活 - 查用户被授予了哪些角色:
SELECT * FROM mysql.role_edges WHERE to_user = 'dev1' AND to_host = '%' - 旧版客户端(如 MySQL 5.7 客户端连 8.0 服务端)可能忽略角色信息,建议用
mysql --version ≥ 8.0.11验证
SET ROLE切换会话角色时权限互斥,不是叠加
执行SET ROLE 'app_writer'后,之前激活的'app_reader'权限立刻失效。这不是bug,是MySQL会话级角色模型的设计逻辑。
-
SET ROLE是即时生效、覆盖式切换,不是追加 - 若需同时使用多组权限,只能设多个默认角色:
SET DEFAULT ROLE 'app_reader', 'app_writer' TO 'dev1'@'%' - 设为
SET DEFAULT ROLE NONE TO表示登录后不自动激活任何角色,哪怕已授予权限 - 即使
SET DEFAULT ROLE成功,若连接时未指定--default-auth=mysql_native_password(尤其旧客户端),角色也可能不加载
真正容易被跳过的不是语法,而是这三步闭环:创建角色 → 给角色GRANT → GRANT角色给用户 → SET DEFAULT ROLE。漏掉任意一环,权限就停在“挂载但未启用”状态。











