必须显式执行REVOKE GRANT OPTION ON . FROM 'user'@'host',因ALL PRIVILEGES不包含GRANT OPTION;需检查并终止旧连接、解绑带GRANT OPTION的角色,FLUSH PRIVILEGES对其无效。

REVOKE GRANT OPTION 必须显式执行,不能依赖 ALL PRIVILEGES
执行 REVOKE ALL PRIVILEGES ON *.* FROM 'user'@'host' 不会动 GRANT OPTION——它被 MySQL 视为独立权限。哪怕用户只剩 USAGE,只要 GRANT OPTION 还在,他就能给其他人授任何权限。这是生产环境最常漏掉的后门。
必须单独撤销:REVOKE GRANT OPTION ON *.* FROM 'user'@'host'。若当初授权范围是库级(如 ON app_db.*),这里也得严格匹配,否则静默失败。
- 查当前是否拥有:
SHOW GRANTS FOR 'user'@'host'—— 输出里若含WITH GRANT OPTION,说明仍可转授 - 全局转授权限只能在
*.*上撤销;写成app_db.*会报错ERROR 1221 - MySQL 8.0+ 中,角色也可能带
GRANT OPTION,需用SHOW GRANTS FOR 'user'@'host' USING 'role_name'检查
撤销后旧连接仍能继续 GRANT,必须主动清理活跃会话
权限变更不自动同步到已建立连接。REVOKE GRANT OPTION 执行完,只要用户没重连,他照样能运行 GRANT SELECT ON sales.* TO 'newuser'@'%'。
验证方式很简单:用该账号新开一个客户端执行 SHOW GRANTS,对比旧会话输出是否已无 WITH GRANT OPTION。不一致就说明旧连接还在生效。
- 查活跃会话:
SELECT ID, USER, HOST, COMMAND, TIME FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'user' - 终止指定连接:
KILL CONNECTION [ID](推荐)或KILL [ID] - 应用侧需重启连接池,否则连接复用会让问题持续数小时甚至数天
角色继承的 GRANT OPTION 更隐蔽,必须解绑或撤销角色
用户自己没被直接授 GRANT OPTION,但绑了角色(如 db_admin),而该角色有 GRANT OPTION ON *.*,那用户照样能转授——SHOW GRANTS FOR 'user'@'host' 默认不显示角色带来的权限。
必须显式检查并处理角色链:SELECT FROM_HOST, FROM_USER, TO_HOST, TO_USER FROM mysql.role_edges WHERE TO_USER = 'user'。
- 查角色权限:
SHOW GRANTS FOR 'user'@'host' USING 'db_admin' - 解绑角色:
REVOKE 'db_admin' FROM 'user'@'host' - 若需保留角色但去掉转授权,得进角色本身改:
REVOKE GRANT OPTION ON *.* FROM 'db_admin'@'%'
别信 FLUSH PRIVILEGES,它对 GRANT OPTION 变更无效
在 MySQL 8.0+ 中,FLUSH PRIVILEGES 对 REVOKE GRANT OPTION 类动态权限变更完全不生效——权限缓存由服务端自动管理,这条命令只影响直接修改 mysql.user 等系统表后的场景。
执行完 REVOKE GRANT OPTION 后立刻 FLUSH PRIVILEGES,既不加速生效,也不增强安全性,反而可能在高负载时引发短暂锁表。
- 真正有效的验证动作只有两个:新连接
SHOW GRANTS、杀掉旧连接 - 如果用了外部权限同步工具(如 ProxySQL 或自研中间件),要确认它是否监听了权限变更事件,否则可能缓存过期
- MySQL 5.7 及更早版本中
FLUSH PRIVILEGES是必需的,但 2026 年绝大多数生产实例已是 8.0+,这点极易误判
回收 GRANT OPTION 的关键盲区不在语法,而在连接生命周期和角色继承路径——这两处不处理,等于只关了门,却忘了锁窗。











