REVOKE GRANT OPTION必须使用ON .,因它是全局元权限;错误写法会报ERROR 1221或1064;需先撤业务权限再撤GRANT OPTION,或合并执行,并验证SHOW GRANTS输出。

REVOKE GRANT OPTION必须搭配ON *.*使用
全局GRANT OPTION不能在库级或表级对象上撤销,MySQL会直接报错:ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES。哪怕用户当初只在myapp.*上被授予了WITH GRANT OPTION,撤销时也必须回到全局层级操作——因为GRANT OPTION本身是独立于具体数据库的元权限,只存在于*.*作用域。
正确写法只有这一种:REVOKE GRANT OPTION ON *.* FROM 'admin'@'%';
常见错误包括:
- 写成
REVOKE GRANT OPTION ON myapp.* FROM 'admin'@'%'→ 语法错误 - 漏掉
ON *.*,只写REVOKE GRANT OPTION FROM 'admin'@'%'→ 报错ERROR 1064 (42000) - 用
DROP USER代替——虽然能清掉,但属于“杀鸡用牛刀”,且不可逆
ALL PRIVILEGES不包含GRANT OPTION,必须显式单独撤
执行REVOKE ALL PRIVILEGES ON *.* FROM 'admin'@'%'后,该用户仍保有转授权能力。这是生产环境最常被忽略的高危疏漏:权限看起来“全没了”,但用户还能给其他人授SELECT甚至DROP权限。
必须分两步走:
- 先撤业务权限:
REVOKE ALL PRIVILEGES ON *.* FROM 'admin'@'%'; - 再撤转授权:
REVOKE GRANT OPTION ON *.* FROM 'admin'@'%';
想一步到位?用合并写法:REVOKE ALL PRIVILEGES, GRANT OPTION ON *.* FROM 'admin'@'%';
撤销后已连接会话仍可继续授予权限
权限变更对当前连接不生效。如果admin用户正连着一个长连接(比如应用连接池里的空闲连接),他仍能执行GRANT SELECT ON sales.* TO 'report'@'%',直到断开重连。
这意味着:
- 不能仅靠
REVOKE命令就认为风险已解除 - 需配合主动踢掉活跃连接:
KILL CONNECTION <code>id;(查SHOW PROCESSLIST获取) - 或临时锁定账号:
ALTER USER 'admin'@'%' ACCOUNT LOCK;(MySQL 5.7.6+)
验证是否真正失效,只看SHOW GRANTS输出
别信“执行成功”提示。执行完必须立刻验证:SHOW GRANTS FOR 'admin'@'%';
理想结果只应剩一行:GRANT USAGE ON *.* TO 'admin'@'%'
如果还看到GRANT ... WITH GRANT OPTION或任何GRANT OPTION字样,说明没撤干净。尤其注意:
- 用户可能有多个
host记录(如'admin'@'10.20.30.%'和'admin'@'localhost'),要逐个检查 - 若用户被赋予过角色(如
'dba_role'),角色里也可能带GRANT OPTION,得查SHOW GRANTS FOR 'admin'@'%' USING 'dba_role';
真正难处理的,永远不是那条REVOKE语句本身,而是你不知道权限从哪来、又藏在哪。


















