flush privileges 有时无效,是因为权限修改未写入磁盘、缓存未及时更新或已有连接不重载权限;应优先使用 grant/revoke,避免手改表,并注意 mysql 8.0+ 权限缓存机制及认证插件兼容性。

为什么 FLUSH PRIVILEGES 有时没用
不是命令错了,而是你改的权限根本没写进磁盘——比如直接 UPDATE 了 mysql.user 表但没加 WHERE 条件,或者误操作改了错误行;也可能是 MySQL 正在用缓存中的旧权限,而你刚执行完 FLUSH PRIVILEGES 就立刻用新账号连,结果发现还是拒绝访问。这是因为权限加载是会话级的:已存在的连接不会自动重载权限,只有新连接才会读取刷新后的内存快照。
常见错误现象:Access denied for user 持续出现,哪怕确认 SELECT * FROM mysql.user 里字段值已更新、FLUSH PRIVILEGES 也执行成功。
- 必须确保修改的是正确的用户记录(注意
User和Host组合唯一) -
FLUSH PRIVILEGES不修复语法错误或逻辑错误的 SQL 修改(比如把Select_priv改成'Y'是对的,改成'YES'就无效) - 已有连接不会感知变更,得断开重连,或用
KILL主动终止会话
用 GRANT / REVOKE 替代手改表更安全
直接 UPDATE mysql.user 容易漏掉关联表(比如 mysql.db、mysql.tables_priv),而且字段含义复杂(authentication_string vs password_expired)、大小写敏感、加密方式随版本变(caching_sha2_password 默认启用后,明文密码字段不再生效)。
使用场景:新增用户、增删库表级权限、重置密码。
-
GRANT SELECT ON mydb.* TO 'u1'@'localhost'自动触发权限重载,无需手动FLUSH -
REVOKE INSERT ON mydb.t1 FROM 'u1'@'localhost'同样实时生效 - 如果用了
WITH GRANT OPTION,记得检查被授权者是否还能继续转授——这个状态不会因FLUSH改变,只由GRANT语句控制
MySQL 8.0+ 的权限缓存行为有变化
8.0 开始引入权限缓存(privilege cache),默认开启且不可关闭。它会把权限元数据缓存在内存中加速校验,但也会导致“改了表却没立刻生效”的错觉。
性能影响:缓存提升鉴权速度约 15–20%,尤其高并发短连接场景;兼容性影响:如果你依赖老脚本反复 UPDATE + FLUSH,现在要加 SLEEP(0.1) 或显式 FLUSH OPTIMIZER_COSTS(无关,别乱加)来规避时序问题——其实没必要,改用 GRANT 就行。
-
SHOW VARIABLES LIKE 'flush_time'和权限缓存无关,别被名字误导 - 真正控制缓存的是
performance_schema下的user_defined_functions表?不,它和权限无关——权限缓存没有对应系统变量可调 - 怀疑缓存未更新?查
SELECT USER(), CURRENT_USER()确认当前会话用的是哪个身份,再比对mysql.user中该组合的权限字段
忘记密码后重置权限的典型翻车点
跳过权限验证启动(--skip-grant-tables)后,很多人直接 UPDATE mysql.user SET authentication_string = PASSWORD('new'),结果重启后登录报错 Client does not support authentication protocol。
原因:MySQL 8.0 默认认证插件是 caching_sha2_password,而 PASSWORD() 函数返回的是旧的 mysql_native_password hash 格式,不匹配。
- 正确做法是:
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'newpass' - 如果非要手改表,得同时更新
plugin字段为'caching_sha2_password',且authentication_string值必须是 SHA256 加密后的字符串(可用SHA2('newpass',256)生成,但不推荐) -
FLUSH PRIVILEGES在--skip-grant-tables模式下无效,此时权限系统根本没加载,靠的是内存直通模式
最麻烦的不是命令记不住,而是以为自己改对了——比如 Host 写成 '%' 却忘了它不匹配 localhost(Unix socket 连接走的是 'localhost',不是 '%'),这种细节一漏,刷十次 FLUSH 都没用。











