mysql中角色是权限的命名集合,不独立存在且需显式激活;权限是原子操作,直接生效并按层级短路匹配;角色适用于多人共用权限的批量授权场景。

权限是原子操作,角色是权限的命名集合
MySQL里没有“独立存在的角色权限”,角色本身不执行任何操作,它只是把一堆权限打包命个名。比如app_reader这个角色,背后实际是SELECT、SHOW VIEW等几条GRANT语句的集合。用户不SET ROLE,这些权限就等于没给——哪怕你早就GRANT 'app_reader' TO 'dev'@'%'了。
权限则不同,它是数据库能识别的最小授权单位,比如SELECT、UPDATE、ALTER ROUTINE,每一条都可单独授予、回收,且立即参与权限校验。
- 权限直接生效(执行
GRANT后需FLUSH PRIVILEGES仅在极少数直改系统表场景才需要) - 角色必须显式激活:
SET DEFAULT ROLE 'app_reader' TO 'dev'@'%'或会话中SET ROLE 'app_reader' - MySQL 5.7及更早版本压根不支持
CREATE ROLE,会报错ERROR 1064
权限按层级短路匹配,角色不改变匹配逻辑
MySQL查权限时根本不管角色,它只看四层系统表:mysql.user → mysql.db → mysql.tables_priv → mysql.columns_priv,一旦某层匹配到'Y'就立刻返回,后面全跳过——不是叠加,也不是求并集。
举个典型陷阱:你在mysql.user里把Select_priv设成'Y',那该用户对所有库都有SELECT权;哪怕你在mysql.db里对mall库设了Select_priv = 'N',也完全无效。
- 角色里的权限最终还是会落到这四层表中(比如
GRANT SELECT ON mall.* TO 'app_reader',实际写入mysql.db) -
SHOW GRANTS FOR 'dev'@'%'默认不显示角色赋予的权限,得加USING 'app_reader'才能看到 - 已登录用户不会自动感知角色权限变更,必须重连或手动
SET ROLE
什么时候该用角色?看是否“多人共用同一组权限”
单点授权别硬套角色:给DBA开一个临时备份账号,直接GRANT RELOAD, LOCK TABLES ON *.* TO 'backup_user'@'10.0.1.%',干净利落。
但如果你要给12个报表开发人员统一开通SELECT权限访问sales、customer、order三个库,还可能随时增减人——这时候不用角色,每次都要重复6条GRANT,漏一条就出问题。
- 角色适合横向复用:同岗位、同职能、同项目组的批量授权
- 角色支持嵌套:
GRANT 'app_reader' TO 'app_writer',但禁止循环(A→B→A) - 角色不能登录,也不存于
mysql.user表,只在mysql.role_edges和mysql.default_roles里维护关系
用户、主机、权限三者绑定,角色不能绕过这个前提
MySQL里'dev'@'localhost'和'dev'@'%'是两个完全独立的账户,权限互不影响。角色也一样:你给'dev'@'%'授了角色,'dev'@'localhost'照样啥都没有。
很多线上事故就出在这儿:测试环境用localhost连,生产用%,结果角色只配了后者,一上生产就报Access denied。
- 创建用户时务必写全主机名,别依赖默认值
- 用
SELECT Host, User FROM mysql.user WHERE User = 'dev'确认账户是否存在且主机匹配 - 角色权限生效前,先确保
SELECT权限本身在对应层级(库/表)已正确写入系统表
角色不是银弹,它解决的是“批量分发”问题,而不是“权限逻辑简化”问题。真正容易被忽略的,是权限短路匹配机制和主机粒度隔离——这两点不搞清,哪怕角色用得再规范,也会在某个凌晨三点的发布窗口突然失效。










