绝大多数情况下grant后无需执行flush privileges;mysql会自动重载权限缓存,仅当直接修改mysql.user表时才需该命令;权限生效依赖连接重建或对应操作触发,且账号、实例、大小写等细节必须严格匹配。

GRANT 后到底要不要执行 FLUSH PRIVILEGES;
绝大多数情况下——不用。只要你用的是标准 GRANT 或 REVOKE 语句,MySQL 会自动重载权限缓存,新连接立刻生效。FLUSH PRIVILEGES; 不是“保险丝”,而是“急救锤”:只在你绕过授权语法、直接改 mysql.user 表时才真正需要。
- 执行
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; - 直接
UPDATE mysql.user SET Select_priv='Y' WHERE User='u';→ 必须配FLUSH PRIVILEGES;,否则内存缓存永远不更新
为什么刚授权的用户还是 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语句根本不会写入表,任何刷新都无效 - 权限表字段大小写敏感:Linux 下
'ROOT'@'localhost'≠'root'@'localhost',SELECT查询时也需严格匹配
真正卡住人的,往往不是“怎么加权限”,而是“加给谁、连到哪、什么时候认”。别急着刷缓存,先确认连接字符串和账号 Host 字符串是否一字不差。










