MySQL 权限检查发生在每次查询执行前
MySQL 不是只在登录时校验一次权限,而是在每个 SQL 语句执行前都做权限检查——包括
SELECT、
INSERT、
UPDATE、
DELETE,甚至
SHOW类语句。这意味着:只要用户有权限表(
mysql.user、
mysql.db等)中对应记录,每次查询都会触发一次或多轮权限匹配逻辑。
常见被忽略的场景:
使用通配符授权(如'user'@'%'或
GRANT ... ON *.*)不会跳过检查,只是匹配规则更宽泛 启用
skip-grant-tables才真正绕过权限系统,但此时整个实例无安全防护 代理用户(
PROXY)会额外增加一层映射开销
权限表过大或未优化会拖慢查询响应
权限检查依赖
mysql.user、
mysql.db、
mysql.tables_priv等 MyISAM 表(MySQL 8.0+ 改为 InnoDB,但逻辑不变)。如果这些表里存在大量细粒度授权记录(比如为每个表单独
GRANT),MySQL 就得扫描更多行来确认权限。
典型低效配置:
数百个'app_user'@'10.0.%.%'这类带网段的 Host 条目,导致匹配时需逐行正则比对 用
GRANT ... ON `db_x*`.`t_y*`这类通配符库/表名,触发更复杂的字符串匹配路径 MySQL 5.7 及以前版本中,
mysql.db表未对
Host和
Db字段建联合索引,全表扫描概率高
可通过以下方式观察开销:
SELECT * FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT LIKE '%SELECT%' AND SCHEMA_NAME = 'mysql' ORDER BY SUM_TIMER_WAIT DESC LIMIT 5;
若发现大量
SELECT对
mysql.*表的访问,说明权限检查本身正在成为瓶颈。
启用 roles 或 dynamic privileges 会轻微增加解析负担
MySQL 8.0 引入的
ROLE和动态权限(如
BACKUP_ADMIN)不是纯语法糖。每次执行语句前,MySQL 需展开角色继承链,并合并所有显式授予 + 角色授予的权限集。这个过程涉及多次字典表查询和内存结构构建。
影响程度取决于:
单个用户被赋予的角色数量(>5 个角色时差异开始可测) 角色之间是否存在嵌套(SET ROLE role_a, role_b比
SET DEFAULT ROLE开销略高) 是否频繁切换角色(
SET ROLE本身不慢,但后续每条语句都要重算有效权限)
验证方法:
SELECT USER(), CURRENT_ROLE(), IS_ROLE_ENABLED('app_role');配合
performance_schema.setup_instruments中开启
statement/sql/set_option可定位角色相关语句耗时。
权限配置不当引发隐式锁或元数据锁争用
最隐蔽的性能干扰来自权限与元数据锁(MDL)的交互。例如:
执行SHOW GRANTS FOR 'u'@'h'会获取
mysql.*表的 MDL_SHARED_READ 锁,若此时有人正在
FLUSH PRIVILEGES(需 MDL_EXCLUSIVE),就会阻塞
GRANT/
REVOKE操作本身要写
mysql.*表,触发全局刷新缓存,可能让其他线程短暂等待权限缓存重载 某些监控工具(如 Percona Toolkit 的
pt-heartbeat)若用低权限账号运行,反复失败重试,反而制造大量无效权限检查请求
这类问题不会出现在慢日志里,但会在
performance_schema.metadata_locks中暴露等待链。
真正要注意的不是“要不要配权限”,而是“别让权限管理行为本身变成高频操作”——比如避免定时脚本每分钟
GRANT一遍,或用
SELECT查询
mysql.user做状态同步。
