mysql权限验证在连接建立时完成,连接器立即校验'user'@'host'三元组并加载全部权限到会话内存,后续sql均基于该快照执行;权限检查按user→db→tables_priv→columns_priv层级短路匹配;grant/revoke修改仅对新连接生效,flush privileges不刷新已有连接。

权限验证发生在连接器阶段,不是执行SQL时才检查
用户权限验证在建立连接的第一时间就完成了,不是等到你敲下SELECT或INSERT才去查。你执行mysql -u user -p输入密码后,连接器立刻做两件事:先校验mysql.user表里的用户名、密码哈希、客户端IP(即'user'@'host'三元组),通过后再一次性加载该用户全部权限到当前会话内存中。
这意味着:
• 后续所有SQL语句的权限判断,都基于这个“快照”,哪怕管理员此时用GRANT改了权限,也不会影响已连上的连接;
• FLUSH PRIVILEGES只对新连接生效,对已有连接完全无效;
• 错误如ERROR 1142 (42000): SELECT command denied to user,说明权限快照里没开对应操作,不是语法或表不存在。
权限检查顺序是 user → db → tables_priv → columns_priv
当你要访问某张表的某个字段时,MySQL不会只看user表就放行,而是按固定层级逐级匹配:
- 先查
mysql.user:如果Select_priv = 'Y',直接允许查所有库所有表所有列,不再往下查; - 否则查
mysql.db:看当前USE db_name选中的库是否对该用户开放Select_priv; - 再查
mysql.tables_priv:针对具体表(比如users)是否有Table_priv; - 最后查
mysql.columns_priv:仅当你SQL里明确写了某列(如SELECT phone FROM users),且该列在columns_priv里被单独设为'Y'才放行。
注意:SHOW GRANTS FOR 'user'@'host'显示的是最终合并结果,但实际校验是分步短路的——只要某一层满足,就停止后续检查。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
current_user() 和 user() 的区别直接影响权限判断
你登录时写的账号不等于你实际拥有的权限。比如用mysql -u admin -h 192.168.1.100连上,USER()返回'admin'@'192.168.1.100',但CURRENT_USER()可能返回'admin'@'192.168.%'——因为MySQL按Host精确度匹配,192.168.%比%更优先,所以真正生效的是后者对应的权限记录。
常见陷阱:
- 创建了
'app'@'10.0.0.%'和'app'@'%'两个用户,从10.0.0.5连接时,永远匹配前者,后者权限再高也无效; - 误以为
'root'@'localhost'能远程连,其实localhost在MySQL里特指socket连接,'root'@'%'才是通配远程; - 用
CREATE USER 'u'@'%' IDENTIFIED BY 'p'建完用户,却忘了GRANT,此时current_user()能查到,但所有操作都会报ERROR 1045或1142。
权限变更何时生效?取决于修改方式和作用域
权限不是改完立刻全局生效的,不同场景下延迟不同:
- 用
GRANT/REVOKE修改:已存在连接的权限不变,新连接立即生效; - 手动
UPDATE mysql.user后没FLUSH PRIVILEGES:更改根本不会加载进内存,相当于白改; - 改
mysql.db表:下次执行USE db_name时才重新读取该库权限; - 改
mysql.columns_priv:下一条涉及该列的SQL才会触发重新校验。
最易忽略的一点:长连接空闲超wait_timeout(默认8小时)会被服务端断开,重连时才加载最新权限——所以线上服务若长期不重启,权限更新可能“看不见”。










