执行器字段级权限检查发生在打开表之后、读取数据之前,精确校验如users.phone列权限,不依赖连接器的粗粒度快照,需在调用ha_read_first前完成;因权限快照不刷新,长连接需validationquery或mysql_reset_connection感知变更。

执行器字段级权限检查发生在打开表之后、读取数据之前
执行器的权限检查不是“走个过场”,而是真实访问字段前的最后一道闸门。它不依赖连接器缓存的粗粒度权限(比如“对 users 表有 SELECT 权限”),而是精确到 users.phone 这样的列——哪怕你有整张表权限,只要 columns_priv 里没开这一列的 SELECT,执行器在调用 handler::ha_read_first 前就会中断并报错:ERROR 1142 (42000): SELECT command denied to user 'app'@'%' for column 'phone' in table 'users'。
为什么不能只靠连接器或预处理器检查?
连接器只做用户身份认证和初始权限快照加载;预处理器能发现“表不存在”或“列名拼错”这类语义错误(ERROR 1054),但无法覆盖动态权限场景:
- 视图定义中引用了受控字段,而视图本身权限宽松——执行器必须在展开视图后、真正读取底层字段时再验一次
- 存储过程内嵌
SELECT * FROM users,但调用者只被授予部分列权限——预处理器看到的是“查视图”,执行器才看到“查 users.phone” -
GRANT SELECT (id, name) ON users TO 'app'@'%'这种列级授权,只有执行器在字段访问路径上才能触发校验
权限快照不刷新导致的典型误判
执行器用的是连接建立时从 mysql.columns_priv 加载的权限快照,不是实时查表。这意味着:
- 管理员刚执行
GRANT SELECT (phone) ON users TO 'app'@'%'并FLUSH PRIVILEGES,已有连接仍会报ERROR 1142 -
FLUSH PRIVILEGES只刷新内存快照,不重置已存在连接的上下文 - 应用若使用长连接池(如 HikariCP),必须配置
validationQuery=SELECT 1或启用mysql_reset_connection()才能感知权限变更
执行器权限检查影响 JOIN 和多引擎查询
当 SQL 涉及跨引擎 JOIN(如 InnoDB 表联 MyISAM 表),执行器要协调多个存储引擎的字段访问权限:
- 即使两个表各自权限都够,执行器仍需分别校验每个字段是否被授权
- 若
JOIN条件中用了未授权字段(如ON a.phone = b.mobile),错误会在执行器首次尝试读取a.phone时抛出,而非优化器阶段 - 这种检查是逐字段、逐引擎发生的,没法提前合并或跳过
权限检查的位置很关键:它卡在“准备调存储引擎接口”那一瞬间。不是为了重复劳动,而是因为只有到那一步,执行器才真正知道你要读哪个表、哪一列、用哪种引擎——更细的控制,只能放在更晚的时机做。











