MySQL权限通过加载mysql系统表到内存缓存生效,按user→db→tables_priv→columns_priv→procs_priv逐层匹配;GRANT自动刷新权限,REVOKE安全回收,8.0+支持角色管理。

MySQL 授权表结构与权限生效原理
MySQL 的权限不是实时计算的,而是启动时或执行 FLUSH PRIVILEGES 后从系统库 mysql 的几张表中加载进内存缓存。核心表包括:user(全局权限)、db(数据库级)、tables_priv(表级)、columns_priv(列级)和 procs_priv(存储过程级)。权限判断按“最大匹配原则”逐层下推:先查 user 表是否允许连接,再查 db 表是否允许访问某库,以此类推。
常见误操作是改了 mysql.user 表但没执行 FLUSH PRIVILEGES,导致新权限不生效;或者用 UPDATE 直接改表却忽略了 authentication_string 字段加密方式变化(如 5.7+ 默认用 caching_sha2_password),造成用户无法登录。
GRANT 语句的权限粒度与常见陷阱
GRANT 是推荐的授权方式,它自动更新权限表并刷新内存(无需手动 FLUSH),但必须注意语法细节:
-
GRANT SELECT ON mydb.* TO 'u1'@'192.168.1.%'中的mydb.*是数据库+通配符,不能写成mydb(会报错)或mydb.table1(那是表级,需用GRANT SELECT ON mydb.table1) - 主机名
'%'允许任意 IP,但不包括本地 Unix socket 连接('localhost'是特殊值,走 socket,与'127.0.0.1'不等价) - 授予
ALL PRIVILEGES不包含GRANT OPTION,后者必须显式添加,否则该用户无法转授权限 - MySQL 8.0 起移除了
FILE、PROCESS、SUPER等部分高危权限的默认继承,且CREATE USER权限需单独授予
如何安全回收权限并避免锁表风险
权限回收用 REVOKE,但要注意两点:一是它不会删除用户账号本身(要删用户得用 DROP USER),二是某些旧版本(如 5.6)在高并发下执行 REVOKE 可能触发 mysql.db 表的元数据锁,阻塞其他 DDL。
实操建议:
- 优先用
REVOKE SELECT ON mydb.* FROM 'u1'@'%',而非直接 DELETE 权限表行 —— 后者绕过权限校验机制,易引发不一致 - 回收全部权限后,检查是否残留
GRANT OPTION:运行SHOW GRANTS FOR 'u1'@'%'确认输出仅剩USAGE - 若需批量清理,避免在业务高峰执行多条
REVOKE;可先生成脚本,再在维护窗口内集中运行
MySQL 8.0+ 的角色(ROLE)机制怎么用
角色是复用权限集的最简方案,适合团队协作场景。创建角色后,把权限授予角色,再把角色赋予用户,后续只需调整角色权限即可批量生效。
关键步骤:
- 创建角色:
CREATE ROLE 'app_reader' - 赋予权限:
GRANT SELECT ON prod_db.* TO 'app_reader' - 分配角色:
GRANT 'app_reader' TO 'dev1'@'%'(注意:MySQL 8.0 默认不激活角色,需额外执行SET DEFAULT ROLE 'app_reader' TO 'dev1'@'%') - 激活后,用户登录即拥有该角色权限;也可临时启用:
SET ROLE 'app_reader'
容易忽略的是:角色本身没有密码,不能直接登录;且 REVOKE 用户的角色权限时,不会级联撤销角色已有的权限定义 —— 角色仍存在,只是未被分配。










