MySQL权限检查在每次查询前执行而非仅登录时,涉及多表匹配与角色展开,配置不当会引发性能瓶颈和元数据锁争用。

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 需展开角色继承链,并合并所有显式授予 + 角色授予的权限集。这个过程涉及多次字典表查询和内存结构构建。
CRMEB Min是CRMEB品牌全新推出的一款轻量级、高性能、前后端分离的开源电商系统,完善的后台权限管理、会员管理、订单管理、产品管理、客服系统、CMS管理、多端管理、页面DIY、数据统计、系统配置、组合数据管理、日志管理、数据库管理,一键开通短信、产品采集、物流查询等接口,系统采用TP6+Mysql+Uniapp+iView+Redis+workerman+form-builder等最流行热
影响程度取决于:
- 单个用户被赋予的角色数量(>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 做状态同步。










