绝大多数情况下GRANT后无需执行FLUSH PRIVILEGES;它仅在直接修改mysql系统表时才需要,标准授权语句会自动重载权限缓存,且权限检查只发生在连接建立时,已存在连接须重连才生效。

GRANT之后要不要执行FLUSH PRIVILEGES?
绝大多数情况下——不用。只要你用的是标准GRANT或REVOKE语句,MySQL 会自动重载权限缓存,新连接立刻生效。FLUSH PRIVILEGES不是“保险丝”,而是“急救锤”:只在你绕过授权语法、直接UPDATE mysql.user或INSERT INTO mysql.db改系统表时才真正需要。
- 执行
GRANT SELECT ON mydb.* TO 'u'@'localhost';后再跟一句FLUSH PRIVILEGES;,语法合法但纯属冗余 - 冗余执行可能让你误以为“不刷就不生效”,从而忽略真实问题(比如没重连、主机名写错)
- 怀疑自己是否用了标准语句?查操作记录:
SELECT * FROM mysql.general_log WHERE argument LIKE '%GRANT%' ORDER BY event_time DESC LIMIT 3;
为什么刚授权的用户还是Access denied?
不是权限没加对,而是 MySQL 的权限检查只发生在连接建立那一刻。已存在的连接不会动态感知权限变更——哪怕你刚给它加了ALL PRIVILEGES。
- 必须断开重连:客户端执行
QUIT;,再重新运行mysql -u u -p -h localhost -
'u'@'localhost'和'u'@'127.0.0.1'是两个完全不同的账号:前者走 Unix socket,后者走 TCP/IP - 授权语句里多一个空格(比如
'u '@'localhost')就匹配不上;大小写、引号、单双引号混用也会导致失效 - MySQL 8.0+ 默认认证插件是
caching_sha2_password,老版本客户端(如某些 Python MySQL 驱动)可能静默降级失败,表现为“连得上但权限不对”
不同粒度权限的生效时机完全不同
不能一概而论“改完就该能用”。MySQL 对权限粒度做了精细控制,生效时机取决于你授的是哪一级权限:
-
GRANT SELECT ON *.*(全局权限)→ 只对新连接生效,当前会话立即失效 -
GRANT SELECT ON db1.*(数据库级)→ 下次执行USE db1;才生效,当前会话仍无权访问该库 -
GRANT SELECT ON db1.t1(表级)→ 下次对该表发起查询(如SELECT * FROM t1;)即生效,无需USE
最容易被忽略的三个硬坑
权限“看起来没变”,常常根本不是权限本身的问题:
- 连错了实例:本地同时跑着 Docker、Homebrew、系统自带多个 MySQL,
mysql -u u -p默认连的是 socket 路径,而你改权限的可能是mysql -h 127.0.0.1 -P 3307那个 - 启动参数干扰:
--skip-grant-tables模式下所有权限校验被跳过,此时GRANT语句根本不会写入表,任何刷新都无效 - 配置文件权限过大:如果
/etc/mysql/mysql.conf.d/mysqld.cnf是 world-writable(-rwxrwxrwx),MySQL 会直接忽略它,并在错误日志里报[Warning] World-writable config file ... is ignored
权限生效这件事,卡在连接、匹配、缓存、加载四个环节里的任何一个,都会表现成“改了没用”。最省时间的做法,永远是先确认你连的是哪个实例、用的是哪个账号、走的是哪种协议、有没有真正重连——而不是急着去刷权限。










