FLUSH PRIVILEGES仅在直接UPDATE/INSERT系统权限表时必需,它强制重载磁盘权限至内存ACL缓存,不影响已存在连接,新连接才生效;GRANT/ALTER USER等语句自动同步,无需执行。

权限只在连接建立时加载,已存在连接不会更新
MySQL 的权限检查不是实时的,而是“快照式”的:每个连接在认证成功那一刻,服务端就从磁盘读取该 CURRENT_USER() 对应的所有权限,固化到内存中并绑定到该连接线程。后续所有 SQL 执行都查这个内存副本,完全不触碰磁盘表。
这意味着:GRANT 成功后,当前会话里的任何操作(哪怕刚执行完 GRANT SELECT ON *.* TO 'u'@'h')仍用旧权限。必须主动断开:
- 客户端执行
QUIT;或EXIT; - 用完全相同的参数重连,例如:如果授权的是
'u'@'127.0.0.1',就别用mysql -u u -p(默认走 socket,匹配'u'@'localhost') - 应用服务要重建连接池,不能只重启进程而不关闭活跃连接
你连的用户和你授的用户根本不是同一个
CURRENT_USER() 和 USER() 经常不同——前者才是 MySQL 实际匹配到的账号,后者只是你声明的身份。权限是否生效,只取决于 CURRENT_USER() 对应的那条记录是否存在且字段正确。
常见错配场景:
-
'u'@'localhost'和'u'@'127.0.0.1'是两条独立账号,socket 连接匹配前者,TCP 连接匹配后者 - 多一个空格:
'u '@'localhost'≠'u'@'localhost' - DNS 解析开启时,
'u'@'%'可能因反向解析失败而 fallback 到 IP,但你没给那个 IP 授权 - 本地多个 MySQL 实例共存(Docker、Homebrew、系统自带),
mysql -u u -p默认连 socket,而你GRANT的是mysql -h 127.0.0.1 -P 3307那个实例
不同粒度权限的生效时机完全不同
别指望“改完就能用”。MySQL 对权限粒度做了硬性区分,生效行为由作用域决定:
-
GRANT SELECT ON db.t TO 'u'@'h'(表级):下次执行SELECT * FROM t就生效,当前连接内可立即用 -
GRANT SELECT ON db.* TO 'u'@'h'(库级):执行USE db后立即生效,无需重连 -
GRANT SELECT ON *.* TO 'u'@'h'(全局级):仅对新连接生效,当前连接无论USE多少次都没用
混淆这三者,就会误判“权限没生效”,其实只是还没触发对应动作。
别乱用 FLUSH PRIVILEGES,它解决不了连接缓存问题
FLUSH PRIVILEGES 只做一件事:强制从磁盘重新加载权限表到全局内存缓存。但它对已建立的连接毫无影响——那些连接绑的仍是旧快照。
更关键的是:只要你用的是标准 GRANT / REVOKE 语句,MySQL 5.7+ 和 8.0+ 都会自动刷新缓存,FLUSH PRIVILEGES 纯属冗余。它唯一必要场景是:
- 你绕过语法,直接
UPDATE mysql.user或INSERT INTO mysql.db - 你在 MySQL 8.0+ 中启用了角色但没执行
SET DEFAULT ROLE,此时FLUSH也救不了
真正卡住人的,从来不是“没刷”,而是 CURRENT_USER() 匹配失败、连接没重建、或粒度理解错——这些细节稍有偏差,权限就等于不存在。


















