flush privileges仅在直接修改mysql系统表(如update mysql.user)后必需,用grant/revoke等标准语句则自动同步内存与磁盘,执行该命令多余且可能掩盖错误;它强制全量重载权限表覆盖内存acl,但不影响已存在连接,新权限需重新登录才生效。

绝大多数情况下,执行 FLUSH PRIVILEGES 是多余的,甚至会掩盖真正的问题。 它只在你绕过标准语法、直接修改 mysql.user 等系统表时才必须执行;而用 GRANT、REVOKE、ALTER USER 等语句操作时,MySQL 已自动刷新缓存,加了 FLUSH PRIVILEGES 不报错,但纯属“做了没用的事”。
为什么刚执行 GRANT 还是 Access denied?
不是权限没加对,而是权限检查只发生在连接建立那一刻。已有连接不会动态更新权限,哪怕你刚给它授了 ALL PRIVILEGES。
- 必须断开重连:客户端执行
QUIT;后,再重新运行mysql -u u -p -h host -
'u'@'localhost'和'u'@'127.0.0.1'是两个完全不同的账号——前者走 Unix socket,后者走 TCP/IP,授权和连接必须匹配 - 用户名或 host 多一个空格(如
'u '@'localhost')就查不到对应行,SHOW GRANTS FOR也查不到 - MySQL 8.0+ 默认认证插件是
caching_sha2_password,老版本客户端(如旧版 Navicat、Python MySQLdb)可能静默降级失败:能连上,但权限不生效
哪些场景下真得执行 FLUSH PRIVILEGES?
仅当跳过授权逻辑、直接写系统表时才需要——比如用 UPDATE mysql.user 改密码字段、批量修正 Host 值、或从旧备份导入权限数据后。
- 5.7 及以前:改完
mysql.user必须配FLUSH PRIVILEGES,否则内存缓存仍是旧快照 - 8.0+:手动 UPDATE 极易写错
authentication_string格式或plugin字段,FLUSH PRIVILEGES可能无法修复校验失败,甚至掩盖插件不匹配问题 - 托管环境(如阿里云 RDS、腾讯云 CDB)通常禁用
FLUSH PRIVILEGES,直接报错ERROR 1227 (42501): Access denied - 执行前务必确认 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 或 INSERT 看报错。
最容易被忽略的硬坑:连错了实例或权限表结构异常
本地同时跑 Docker、Homebrew、系统自带多个 MySQL 实例很常见。mysql -u u -p 默认连的是 socket 路径,而你改权限的可能是 mysql -h 127.0.0.1 -P 3307 那个——根本不是同一个实例。
- 升级后权限异常?先查
DESC mysql.user:MySQL 8.0 缺失authentication_string或account_locked字段,说明mysql_upgrade没跑或失败 - 权限表损坏或字段格式不一致时,
FLUSH PRIVILEGES无法修复,需停库后用mysqld --initialize-insecure重建系统库结构 -
account_locked字段不能靠UPDATE设置,必须用ALTER USER 'u'@'h' ACCOUNT LOCK,否则状态不同步且可能被后续FLUSH PRIVILEGES覆盖











