修改权限后已建立连接不生效原因
问题场景
作为 DBA,你可能遇到过这种情况:
-- 1. 给用户授新权限
GRANT SELECT ON db1.* TO 'user1'@'localhost';
-- 2. 但 user1 已有连接还在执行查询
-- 发现:旧连接没有新权限!
-- 必须断开重连后才生效
这是为什么?
根本原因:权限缓存机制
sequenceDiagram
participant User as 客户端
participant Conn as 连接器
participant AuthT as mysql.user表
Note over User,AuthT: 连接建立阶段
User->>Conn: TCP连接+登录
Conn->>AuthT: 读取权限信息
AuthT-->>Conn: 返回权限记录
Conn->>Conn: 缓存到Connection Session内存
Note over Conn: ⭐ 权限在此刻锁定
Note over User,AuthT: 运行阶段
DBA->>AuthT: GRANT 修改权限<br/>修改了表数据
AuthT-->>DBA: ✅ 成功写入
User->>Conn: 执行SQL
Conn->>Conn: ⚡ 直接从缓存读取权限<br/>📌 不重新查表!
Conn-->>User: 使用旧权限<br/>判断操作是否允许
关键点:连接建立后,权限被锁定在当前连接的内存中。
缓存为什么不刷新
1. 性能考虑
graph LR
A[每次SQL都查权限表] --> B[严重性能开销]
B --> C[频繁的磁盘IO]
C --> D[热点行竞争]
D --> E[性能灾难]
F[连接时缓存] --> G[零额外开销]
G --> H[O(1)判断权限]
每执行一条 SQL 就去查一次 mysql.user/mysql.db 等权限表,在高并发场景下是不可接受的。
2. 设计哲学
MySQL 认为:
– 权限变更是低频操作
– 连接缓存是合理的 trade-off
– 如果需要新权限,重新连接即可
验证实验
-- 终端1:user1登录不退出
mysql -uuser1 -p
-- 终端2:DBA修改权限
mysql -uroot -p
GRANT SELECT ON test.* TO 'user1'@'localhost';
FLUSH PRIVILEGES;
-- 终端1:仍然无法看到新权限
SHOW GRANTS;
-- 输出中没有新加的权限(除非重连)
如何让权限立即生效
方法一:断开重连(推荐)
-- 用户端断开
EXIT;
mysql -uuser1 -p
方法二:FLUSH PRIVILEGES
-- DBA执行
FLUSH PRIVILEGES;
注意:FLUSH PRIVILEGES 只重新加载内存中的权限表(影响之后的新连接),已经连接的旧会话依然不受影响。
正确操作顺序
-- 1. 修改权限
GRANT SELECT ON db.* TO 'user1'@'localhost';
-- 2. 重新加载权限表(影响新连接)
FLUSH PRIVILEGES;
-- 3. 通知用户重新连接
例外情况
某些权限操作(如 KILL)可能立即生效,但绝大多数权限修改需要重连。
面试要点
- 根本原因:权限在连接建立时缓存到会话内存,后续不重新查询
- 设计原因:性能优化,避免每条 SQL 都查权限表
- 解决方案:断开重连或提醒用户重新登录
- FLUSH PRIVILEGES 的作用:从磁盘重新加载到全局缓存(不影响已有连接)
一句话总结:MySQL 在连接时”快照”了你的权限,修改权限后旧会话手里的还是”老照片”。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容