直接UPDATE mysql.user表后权限不生效,是因为MySQL将权限表加载进内存缓存,修改磁盘表需执行FLUSH PRIVILEGES强制重载(5.7及以前有效);8.0+版本不推荐直接改表,GRANT语句已自动刷新缓存,且托管环境常禁用FLUSH PRIVILEGES。

直接 UPDATE mysql.user 表后权限不生效,是因为缓存没刷新
MySQL 启动时把权限表加载进内存,后续连接都查这份快照,改磁盘上的 mysql.user 表本身不会触发重载。你看到的“改了没用”,本质是新数据还在磁盘,旧权限还在内存里。
必须执行 FLUSH PRIVILEGES 才能强制从磁盘重新读取并覆盖内存缓存——但仅限于 5.7 及更早版本;8.0+ 中部分字段(如 authentication_string 格式)已变更,手动更新极易写错,FLUSH PRIVILEGES 也可能无法修复校验失败。
- 5.7 及以前:UPDATE +
FLUSH PRIVILEGES是可行路径,但需确认 host、user 拼写完全一致(含空格) - 8.0+:不推荐直接改表,
FLUSH PRIVILEGES对某些非法字段更新无效,甚至可能掩盖认证插件不匹配问题 - 托管环境(如阿里云 RDS、腾讯云 CDB)通常禁用
FLUSH PRIVILEGES,直接报错ERROR 1227 (42501): Access denied
GRANT 后加 FLUSH PRIVILEGES 是多余操作
标准授权语句(如 GRANT SELECT ON db.* TO 'u'@'h')会自动触发权限缓存重载,无需再执行 FLUSH PRIVILEGES。加了不报错,但属于“做了没用的事”,还容易误导你忽略真正的问题。
常见误判场景:
- 执行了
GRANT,也执行了FLUSH PRIVILEGES,但还是连不上 → 实际是没断开重连,旧连接仍用初始化时的权限快照 - 用
SHOW GRANTS FOR 'u'@'h'看到权限已存在 → 这只说明语句执行成功,不代表当前连接能用,得真跑一句SELECT或INSERT验证 - 权限作用域写错,比如用了
'u'@'localhost'却从远程连,或用了'u'@'%'但客户端解析出的是具体 IP,host 不匹配
权限生效时机取决于作用域类型,不是统一刷新
MySQL 权限检查发生在连接建立那一刻,但不同粒度的权限更新对已有连接的影响不同:
- 表级(
db.table)和列级权限:下次对该对象发起请求时立即生效,不用重连 - 数据库级(
db.*)权限:执行USE db后即生效,也不强制重连 - 全局级(
*.*)权限:仅对新连接生效,已有连接必须QUIT后重连才可获得新权限
特别注意:account_locked 字段不能靠 UPDATE 设置,必须用 ALTER USER 'u'@'h' ACCOUNT LOCK,否则状态不同步,日志不记录,且可能被后续 FLUSH PRIVILEGES 覆盖掉。
排查权限不生效时,先确认是否跳过了权限校验
如果改了表、刷了缓存、重连了,还是不行,要立刻检查 MySQL 是否运行在 --skip-grant-tables 模式下:
- 该模式下所有权限逻辑被绕过,
GRANT语句根本不写入表,FLUSH PRIVILEGES也无意义 - 查启动参数:
ps aux | grep mysqld,看输出里是否含--skip-grant-tables - 查错误日志:
mysqld启动时若带该参数,日志中会有明确提示 “Skipping grant tables” - 此时唯一办法是停库、移除该参数、重启,再重新赋权
最常被忽略的一点:权限修改后能否生效,不取决于你敲了多少条命令,而取决于连接建立时 MySQL 读到的是哪份权限快照——它可能来自内存缓存、磁盘表、甚至被启动参数彻底屏蔽。


















