MySQL中REVOKE执行成功后当前会话权限不立即失效,仅修改系统表,活跃连接仍用旧权限快照;撤销须精确匹配GRANT对象范围,且ALL PRIVILEGES不包含隐式USAGE权限。

已建立连接的权限不会随REVOKE动态更新
MySQL 在用户完成认证、建立连接时,会把该用户的全部权限快照固化到会话上下文中。后续执行 REVOKE 只修改 mysql.user、mysql.db 等系统表,并不触碰任何活跃连接的内存状态。所以即使你刚执行了 REVOKE SELECT ON mydb.* FROM 'u'@'%',那个已经连着的会话仍能继续 SELECT——它用的不是“当前权限”,而是“登录那一刻的权限”。
SHOW GRANTS 和实际权限不一致是正常现象
在活跃连接中执行 SHOW GRANTS,返回的是该会话初始化时加载的权限快照,不是实时查系统表的结果。这容易让人误判权限是否生效。
- 验证真实权限变更效果,必须新建连接再测试
-
SELECT * FROM mysql.db WHERE User = 'u'能看到系统表里权限确实被清除了,但这和当前连接无关 - MySQL 8.0+ 中
FLUSH PRIVILEGES对已连会话同样无效,它只影响新连接的权限加载
为什么KILL CONNECTION后新连接就受控了?
真正让权限回收“落地”的动作,是切断旧连接并迫使客户端建新连接。新连接建立时才会重新读取系统表、校验权限、生成新快照。
- 先查连接:
SELECT ID, USER, HOST FROM information_schema.PROCESSLIST WHERE USER = 'u' - 再杀掉:
KILL CONNECTION 123(注意加CONNECTION,否则只中断当前语句) - 客户端若启用了自动重连(如 JDBC 的
autoReconnect=true),可能秒级重建连接——此时权限才真正生效 - 连接池场景下,还需等连接空闲超时或主动驱逐,不能只靠服务端操作
容易被忽略的隐性权限来源
有时你以为收回了所有 SELECT 权限,但用户仍能查数据,原因常藏在这些地方:
-
public角色(MogDB/openGauss 行为):即使REVOKE了用户自身权限,public默认带CONNECT或USAGE,需显式REVOKE CONNECT ON DATABASE db FROM PUBLIC - 全局权限残留:
SELECT_priv = 'Y'在mysql.user表里没清干净,会导致用户能看到所有库名甚至执行查询 - 代理权限(PROXY):MySQL 5.7+ 支持代理用户,
DROP USER不清理mysql.proxies_priv,代理关系可能绕过权限检查 - Navicat / DBeaver 等工具缓存:删完权限后没删连接配置,重连时可能复用旧会话或凭记忆自动重连
权限回收生效的关键不在“删”,而在“断”——断掉旧连接,才能让新权限在新会话里真正起效。


















