修改权限后已建立连接不生效原因

修改权限后已建立连接不生效原因

问题场景

作为 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
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容