根本原因是MySQL将权限表加载进内存缓存,手动修改磁盘表不触发刷新,旧快照仍被连接校验;FLUSH PRIVILEGES仅强制重载,但无法修复字段非法、host不匹配、插件不兼容或--skip-grant-tables等底层问题。

MySQL 无法识别手动修改 mysql.user 等系统表后的权限变更,根本原因在于:**权限不是靠“查表”实时生效的,而是加载进内存缓存后由连接建立时一次性校验的——你改了磁盘上的表,但内存里还是旧快照。**
为什么改了 mysql.user 表却没效果?
MySQL 启动时会把权限数据从磁盘加载到内存中构建 ACL(访问控制列表),后续所有连接都基于这份内存快照做权限判断。直接 UPDATE mysql.user 只改了磁盘数据,不会触发内存刷新,也不会校验字段合法性(比如 authentication_string 格式、plugin 匹配等)。
- MySQL 8.0+ 中
authentication_string是 SHA256 哈希值,且与plugin字段强绑定;手写错一位就导致认证失败,但错误常被静默吞掉 -
password_last_changed、account_locked等字段若非法设置,可能让账户进入不可用状态,而FLUSH PRIVILEGES也无法修复 - 某些托管环境(如阿里云 RDS)直接禁用对
mysql库的写操作,UPDATE语句本身就会报错
FLUSH PRIVILEGES 为什么有时也不管用?
它只是强制重载磁盘权限表到内存,但解决不了底层不匹配问题:
- 如果客户端连的是
'u'@'127.0.0.1',但你只改了'u'@'localhost'这一行,FLUSH PRIVILEGES加载的仍是空权限 - MySQL 8.0+ 默认用
caching_sha2_password插件,而你手动把plugin改成mysql_native_password,但客户端不支持该插件,就会卡在认证阶段,看起来像“权限无效” - 已存在的连接不受影响——新权限只对新建连接生效,
FLUSH PRIVILEGES不会踢掉当前会话 - 若 MySQL 正以
--skip-grant-tables启动,所有权限校验被跳过,FLUSH PRIVILEGES完全无效
哪些权限粒度改完能立即在当前连接里用?
不是所有权限都需重连,MySQL 按作用域做了精细区分:
-
GRANT SELECT ON db1.t1 TO 'u'@'h'(表级):当前连接执行SELECT * FROM t1就生效 -
GRANT SELECT ON db1.* TO 'u'@'h'(库级):当前连接执行USE db1后立即生效 -
GRANT SELECT ON *.* TO 'u'@'h'(全局级):必须断开重连才生效,USE或任何命令都无法绕过
别只信 SHOW GRANTS FOR 'u'@'h',它只显示授权记录,不反映真实生效状态——真跑一条 SELECT 或 ALTER TABLE 看是否报错,才是唯一验证方式。


















