revoke必须明确权限类型、对象和用户:语法为revoke privilege_type on database.object from 'user'@'host';撤销all privileges后仍保留usage权限;需执行flush privileges刷新缓存;用show grants验证结果。

REVOKE 语句必须指定权限类型和对象
MySQL 中撤销权限不能只写 REVOKE user 或类似模糊表达,必须明确「撤什么权限」「从哪个用户」「在哪个范围」。遗漏任意一项都会报错,比如 ERROR 1147 (42000): There is no such grant defined for user 'u1' on host '%' on table '*.*' 就常因权限类型或作用域不匹配导致。
基本语法是:REVOKE privilege_type ON database.object FROM 'user'@'host';
-
privilege_type如SELECT、INSERT、ALL PRIVILEGES(注意不是ALL) -
database.object必须与当初GRANT时完全一致,比如授的是mydb.*,就不能用*.*去撤;授的是mydb.t1,就不能只写mydb.* -
'user'@'host'的 host 部分必须精确匹配,'u1'@'localhost'和'u1'@'%'是两个不同账号
撤销 ALL PRIVILEGES 后仍可能保留 USAGE 权限
执行 REVOKE ALL PRIVILEGES ON *.* FROM 'u1'@'%'; 看似清空所有权限,但 MySQL 默认会给用户保留 USAGE 权限——它不赋予任何实际操作能力,仅表示该账号存在且可连接(前提是密码正确)。所以你查 SHOW GRANTS FOR 'u1'@'%'; 仍会看到 GRANT USAGE ON *.* TO 'u1'@'%'。
这本身不是问题,但容易误判为“权限没撤干净”。真正要彻底禁用账号,应配合 DROP USER 'u1'@'%';,或用 ALTER USER 'u1'@'%' ACCOUNT LOCK;(MySQL 5.7.6+)。
撤销权限后需要手动刷新权限表
MySQL 不会自动重载权限缓存。即使 REVOKE 执行成功,已建立的连接仍保留旧权限,新连接才会生效。必须显式执行:FLUSH PRIVILEGES;
- 不执行这步,用户可能继续执行被撤销的操作,尤其在长连接或应用连接池场景下极易踩坑
-
FLUSH PRIVILEGES是即时生效的全局操作,无返回值,也不报错——执行完没提示不等于没成功 - 部分运维脚本会漏掉这行,结果“以为撤了,其实还在用”
用 SHOW GRANTS 验证撤销是否到位
别只信 REVOKE 的 OK 提示。最稳妥的方式是立刻查授权记录:SHOW GRANTS FOR 'u1'@'%';
重点看两点:
- 输出中是否还包含你要撤销的权限项(如仍有
SELECT就说明没撤对对象或范围) - 是否只剩
GRANT USAGE ON *.*(即已清空业务权限) - 如果用户有多个 host 记录(比如
'u1'@'192.168.%'和'u1'@'localhost'),需分别验证
权限撤销不是一劳永逸的事,尤其是多节点部署或权限由自动化工具管理时,host 匹配、作用域一致性、缓存刷新这三处最容易出偏差。










