GRANT执行后权限是否“立刻可用”取决于权限类型和连接状态:数据库/表级权限对当前连接后续查询即时生效,全局权限(如SUPER)仅新连接生效,角色权限可通过SET ROLE即时切换;MySQL 5.7+自动刷新缓存,无需FLUSH PRIVILEGES,除非直接修改系统表。

GRANT执行后权限何时生效?
权限是否“立刻可用”,取决于权限类型和连接状态,不是统一的。直接用GRANT语句修改后,MySQL 5.7+ 会自动刷新内存缓存,无需手动FLUSH PRIVILEGES——除非你绕过GRANT,用UPDATE mysql.user这类方式改系统表。
但生效范围有区别:
- 数据库/表级权限(如
SELECT ON app_db.users)对当前连接后续查询即时生效(事务中可能延迟到下一条语句) - 全局权限(如
SUPER、REPLICATION CLIENT、CREATE USER)只在连接建立时检查一次,已存在的连接不会感知变更,必须新建连接 - 角色权限(MySQL 8.0.2+)可通过
SET ROLE即时切换,不依赖重连
为什么GRANT有时会卡住或阻塞新连接?
在 MySQL 5.7 及之后版本,GRANT本身不锁数据表,但它需要获取mysql库的元数据锁(MDL)。如果此时有长事务正在读mysql.user,或另一个会话正执行FLUSH PRIVILEGES,GRANT就会被挂起。
后果可能比你想象的严重:被阻塞的GRANT会拖住后续所有新连接尝试(因为新连接要读权限表),引发雪崩式连接堆积。
排查和规避方法:
- 操作前查锁:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA = 'mysql'; - 避开业务高峰,尤其避免在
FLUSH PRIVILEGES刚执行完就立刻GRANT - MySQL 8.0+ 建议禁用
FLUSH PRIVILEGES,它已成冗余操作,还可能触发全局读锁
如何避免误授全局权限导致不可逆风险?
直接GRANT ALL PRIVILEGES ON *.*是生产环境高危操作。一旦执行,撤回不仅麻烦(需逐项REVOKE),还容易遗漏;更糟的是,若用户已被应用复用,突然降权可能直接中断服务。
更安全的替代路径是角色(ROLE)机制(MySQL 8.0.2+ 稳定支持):
- 先建角色:
CREATE ROLE 'app_writer'; - 授权给角色:
GRANT INSERT, UPDATE, DELETE ON order_db.* TO 'app_writer'; - 再把角色赋予用户:
GRANT 'app_writer' TO 'app_user'@'%'; - 设为默认角色:
SET DEFAULT ROLE 'app_writer' TO 'app_user'@'%';
后续调整权限只需改角色定义,不影响已有连接,也不用碰用户本身。注意确认activate_all_roles_on_login是否为ON,否则用户登录后需手动SET ROLE。
权限变更要不要加IDENTIFIED BY?
加IDENTIFIED BY会在授权同时重置密码,这在批量脚本或自动化流程里极易引发意外——比如你只想加个SELECT权限,却顺手把密码改了,导致应用连接失败。
正确做法是分离关注点:
- 权限变更只用
GRANT ... TO 'u'@'h';,不带IDENTIFIED BY - 密码修改单独走
ALTER USER 'u'@'h' IDENTIFIED BY 'newpass'; - 如果用户不存在,才用
CREATE USER+GRANT组合,且确保CREATE USER语句显式指定认证插件(如mysql_native_password),避免因默认插件变更导致兼容性问题
真正容易被忽略的,是角色默认激活和连接复用这两件事——前者不设DEFAULT ROLE,用户连上也拿不到权限;后者让开发误以为“改完就生效”,结果线上查不到新权限,又去反复FLUSH,反而加剧锁竞争。


















