GRANT后权限不生效主因是连接未重建、host匹配错误或权限粒度差异;MySQL仅在连接建立时校验权限,已存在会话不更新,且'localhost'与'127.0.0.1'为不同账号,表级权限当前连接可热生效,全局权限须重连。

GRANT 命令本身已自动刷新权限缓存,不生效几乎从来不是因为“没刷”,而是连接、匹配或粒度问题。
为什么刚 GRANT 完还是 Access denied?
MySQL 权限检查只发生在连接建立那一刻,已有连接不会动态更新权限——哪怕你刚执行了 GRANT ALL PRIVILEGES ON *.* TO 'u'@'h',当前会话仍按旧快照运行。
- 必须断开重连:客户端执行
QUIT;后,再用完全相同的参数重新连接(注意:'u'@'localhost'和'u'@'127.0.0.1'是两个独立账号) - 应用服务需重建连接池,不能只重启进程而不关闭现有连接
- 本地可能同时运行多个 MySQL 实例(Docker、Homebrew、系统自带),
mysql -u u -p默认走 socket,而你授权的可能是mysql -h 127.0.0.1 -P 3307那个实例
不同粒度权限的生效时机完全不同
别指望“改完就能用”,MySQL 对权限更新做了精细控制,生效时机取决于你授的是哪一级:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
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都无效
为什么执行 FLUSH PRIVILEGES 没用甚至有害?
FLUSH PRIVILEGES 只在你绕过标准语法、直接 UPDATE mysql.user 等系统表时才真正需要;用 GRANT 或 REVOKE 时它纯属冗余操作。
- 加了不报错,但掩盖真实问题(比如没重连、host 写错、连错实例)
- MySQL 8.0+ 托管环境(如阿里云 RDS)通常禁用该命令,直接报
ERROR 1227 (42501): Access denied - 若 MySQL 启动时加了
--skip-grant-tables,所有权限校验被跳过,GRANT根本不写表,FLUSH PRIVILEGES完全无效
验证权限是否真生效,别只信 SHOW GRANTS
SHOW GRANTS FOR 'u'@'h' 只说明语句执行成功,不代表当前连接能用。必须真跑一句操作验证:
- 先确认实际认证身份:
SELECT USER(), CURRENT_USER();—— 前者是“你声称是谁”,后者才是 MySQL 实际匹配到的账号 - 再查真实权限:
SHOW GRANTS FOR CURRENT_USER();,看输出里是否有你要的权限及对应作用域(比如ON mydb.*而不是ON *. *) - 最后核对底层数据:
SELECT host, user, select_priv FROM mysql.user WHERE user = 'xxx';,注意字段名在 8.0+ 是authentication_string而非Password
最容易被忽略的,是 CURRENT_USER() 和 USER() 的差异,以及 host 匹配的精确性——多一个空格、大小写不一致、socket vs TCP 的区别,都足以让权限“存在却不可用”。

















