直接UPDATE mysql.user表后权限不生效,是因为MySQL将权限加载进内存缓存,修改磁盘表需执行FLUSH PRIVILEGES强制重载(5.7及以前有效);8.0+不推荐手改表,因authentication_string格式、plugin字段须严格匹配,且托管环境常禁用该命令。

直接UPDATE mysql.user表后权限不生效,是因为缓存没刷新
MySQL启动时把权限数据加载进内存,后续所有连接都查这份快照。改mysql.user表只是写磁盘,不会自动更新内存里的权限状态。你执行完UPDATE mysql.user SET authentication_string = 'xxx'就以为搞定了,但新连接照样报Access denied for user——根本原因是没强制重载。
必须立刻执行FLUSH PRIVILEGES;,否则变更永远不生效。这个命令会从磁盘重新读取mysql.user、mysql.db等表,覆盖内存缓存。注意:5.7及以前版本才依赖它;MySQL 8.0+中该命令对非法字段(如错写password字段)可能静默失败,不报错但也不加载。
- Linux/macOS下临时启动可加
--skip-grant-tables跳过验证,但进去后仍要先FLUSH PRIVILEGES;再改表,否则改完重启还是无效 - Windows上改
my.ini加skip-grant-tables后,必须重启服务才能生效 - 托管环境(如阿里云RDS)通常禁用
FLUSH PRIVILEGES,执行直接报ERROR 1227 (42501)
MySQL 8.0+不能用PASSWORD()函数,authentication_string格式必须匹配插件
在MySQL 8.0+里,PASSWORD()函数已被废弃,且mysql.user表不再有password字段,只保留authentication_string。如果你执行UPDATE mysql.user SET authentication_string = PASSWORD('123'),会触发ERROR 1372 (HY000)。
真正起作用的是plugin字段和authentication_string的组合。比如当前plugin = 'caching_sha2_password',那authentication_string必须是SHA256哈希值;如果强行写成明文或MySQL 5.7风格的哈希,登录时就会认证失败,报1045。
- 查当前配置:
SELECT User, Host, plugin, authentication_string FROM mysql.user WHERE User = 'root'; - 想兼容老客户端(如旧版Navicat、PHP MySQLi),得切回
mysql_native_password:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_pass'; - 切记:不能只改
authentication_string,必须用IDENTIFIED WITH显式指定插件,否则字段和插件不匹配
host字段不匹配是最隐蔽的1045原因
'root'@'localhost'和'root'@'127.0.0.1'在MySQL眼里是两个完全不同的账号,密码一样也不互通。错误信息里写的host,就是你要对准的目标——不是“大概能连上”,而是必须一模一样。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
比如你用mysql -u root -h 127.0.0.1 -p连接,但mysql.user里只有Host = 'localhost'这一行,那就必然失败。反过来,Navicat默认走localhost(socket),如果你只建了'root'@'127.0.0.1',也连不上。
- 确认目标账号是否存在:
SELECT User, Host FROM mysql.user WHERE User = 'root'; - 补缺失host:
CREATE USER 'root'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY 'your_pass'; - 别用
UPDATE mysql.user SET Host = '%'偷懒,生产环境开放'root'@'%'等于裸奔
GRANT OPTION缺失会导致授权语句静默失败
你用root登录,不代表你能给别人授权。MySQL 8.0+默认不给root@'localhost'自带WITH GRANT OPTION,所以执行GRANT ALL ON *.* TO 'app'@'%'时,看起来成功了,其实没生效,后续别人连还是会报Access denied。
查自己有没有这个权限:SHOW GRANTS FOR CURRENT_USER();,看输出里是否含WITH GRANT OPTION。没有就补:GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;。注意:MySQL 8.0+不允许在GRANT语句里带IDENTIFIED BY,必须拆成CREATE USER + GRANT两步。
-
GRANT语句本身会自动刷新缓存,不需要再跟FLUSH PRIVILEGES; - 但如果你是用
UPDATE mysql.user手动改的Grant_priv = 'Y',就必须FLUSH PRIVILEGES;才生效 - 已有连接不会自动获得新权限,必须断开重连
改mysql.user表不是不行,但每一步都要对得上plugin、authentication_string、Host、Grant_priv这四个字段,漏一个就白忙。最常被忽略的是:改完不FLUSH PRIVILEGES,或者以为GRANT后加FLUSH更保险,结果反而掩盖了host不匹配这类底层问题。










