真正回收用户全部权限需四步:先revoke显式权限,再update mysql.user清管理字段并flush privileges,接着撤销空用户对information_schema等的隐式select权限及解绑角色,最后注意usage无法撤销且活跃连接缓存旧权限。

REVOKE ALL PRIVILEGES 本身不包含 GRANT OPTION
执行 REVOKE ALL PRIVILEGES ON *.* FROM 'user'@'host' 后,用户仍可能保留 GRANT OPTION——这意味着他还能给自己或其他人授予权限。这不是“漏撤”,而是 MySQL 的明确设计:ALL PRIVILEGES 列表里压根不包括 GRANT OPTION。必须显式加上它,否则等于留了一把后门钥匙。
常见错误现象:撤销后用户仍能执行 GRANT SELECT ON test.* TO 'other'@'%';查 SHOW GRANTS FOR 'user'@'host' 会看到 GRANT OPTION 仍在输出里。
- 正确写法是:
REVOKE ALL PRIVILEGES, GRANT OPTION ON *.* FROM 'user'@'host' - 如果只针对某个库,比如
app_db,就写:REVOKE ALL PRIVILEGES, GRANT OPTION ON app_db.* FROM 'user'@'host'(注意反引号包裹,防库名含特殊字符) - 别用
REVOKE ALL PRIVILEGES ON *.*去覆盖app_db.*授予的权限——作用域不匹配,不会生效
撤销后旧连接仍持有原权限
执行 REVOKE 成功返回 Query OK,不代表应用立刻失效。已建立的连接不会被强制断开或降权,它们继续按原有权限运行,直到主动断开或超时重连。
验证是否真正生效,必须新开一个连接测试:
- 用
mysql -u user -p -h host重新登录 - 执行
SHOW GRANTS FOR CURRENT_USER;,确认输出只剩GRANT USAGE ON *.* TO ... - 尝试原权限操作(如
SELECT FROM app_db.t1),应报错ERROR 1142 (42000): SELECT command denied...
别忽略角色继承的权限(MySQL 8.0+)
如果用户是通过角色获得权限(例如 GRANT app_reader TO 'user'@'host'),REVOKE ALL PRIVILEGES 完全不影响角色绑定,那些权限依然有效。
必须额外检查并解除角色:
- 查角色绑定:
SELECT * FROM mysql.role_edges WHERE TO_USER = 'user' AND TO_HOST = 'host'; - 撤销角色:
REVOKE app_reader FROM 'user'@'host'; - 若角色本身不再需要,可考虑
DROP ROLE app_reader;
遗漏这步,常导致“明明 revoke 了却还能查数据”的困惑。
USAGE 权限无法撤销,但可锁定账号
USAGE 是 MySQL 默认赋予所有用户的空权限,仅表示“允许连接”(密码正确前提下)。你无法用 REVOKE USAGE 删除它——命令会被忽略,SHOW GRANTS 永远会显示这一行。
如果目标是彻底禁用账号访问(不只是撤权限),不要依赖 REVOKE:
- MySQL 5.7.6+:用
ALTER USER 'user'@'host' ACCOUNT LOCK; - 更彻底:用
DROP USER 'user'@'host';(注意:这会删账号,不可逆) - 临时方案:改密码 +
ACCOUNT LOCK双保险
真正难处理的,从来不是“怎么 revoke”,而是“怎么确认所有路径都断干净”——角色、主机名精度、旧连接、系统库默认访问、information_schema 的宽松策略,都得一个个对上。











