能撤销,但必须严格匹配当初grant时的权限范围、用户标识和作用域;否则看似执行成功实则未生效,需用show grants验证是否真正移除目标权限项。

能撤销,但必须严格匹配当初 GRANT 时的权限范围、用户标识和作用域,否则看似执行成功,实际没撤掉。
REVOKE 必须精确还原 GRANT 的粒度
MySQL 不会“智能推断”你要撤哪层权限。比如当初是 GRANT SELECT ON app_db.users TO 'api'@'10.0.1.%',那撤销就必须写 REVOKE SELECT ON app_db.users FROM 'api'@'10.0.1.%'。不能简写成 REVOKE SELECT ON app_db.*,也不能写成 REVOKE SELECT ON *.*——前者可能漏掉其他表,后者根本撤不到目标对象。
常见错误现象:
- 执行
REVOKE SELECT ON app_db.* FROM 'api'@'10.0.1.%'后,SHOW GRANTS FOR 'api'@'10.0.1.%'仍显示SELECT在app_db.users上 - 误以为撤了全局
INSERT,结果只写了REVOKE INSERT ON mydb.*,漏掉了REVOKE INSERT ON *.*
操作前务必查清原始授权语句(或用 SHOW GRANTS FOR 'user'@'host' 反推),按原样构造 REVOKE。
GRANT OPTION 和 ALL PRIVILEGES 是两回事
ALL PRIVILEGES 不包含 GRANT OPTION,它是独立权限,必须显式撤销。否则用户还能给其他人授权,等于白撤。
正确做法是:
- 只撤业务权限:例如
REVOKE SELECT, INSERT ON sales.* FROM 'reporter'@'%' - 要清空全部(含转授权):必须写
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'reporter'@'%' - 单独撤转授权:用
REVOKE GRANT OPTION ON *.* FROM 'admin'@'%'(注意ON *.*,因为GRANT OPTION是全局级权限)
如果只写 REVOKE ALL PRIVILEGES FROM ...,GRANT OPTION 依然保留,这是最常被忽略的安全缺口。
撤销后权限不立即对已有连接生效
已建立的客户端连接(包括应用连接池里的长连接)不会自动丢弃旧权限,它们仍能继续执行被撤销的操作,直到重连。
这意味着:
- 执行
REVOKE后,立刻用SHOW GRANTS FOR 'user'@'host'验证输出是否已剔除目标权限项 - 别只信
Query OK提示——它只表示语句解析通过,不代表权限真没了 - 若用户有多个 host 记录(如
'u'@'localhost'和'u'@'127.0.0.1'),需分别验证每条 - 生产环境建议配合
ALTER USER 'u'@'h' ACCOUNT LOCK(MySQL 5.7.6+)或直接DROP USER彻底禁用
真正影响业务的不是 REVOKE 本身,而是连接复用机制下权限“延迟失效”这个隐性窗口。
FLUSH PRIVILEGES 不是必需,但验证比刷新更重要
MySQL 8.0+ 中,REVOKE 命令本身会自动刷新权限缓存,FLUSH PRIVILEGES 并非生效前提;它只在你手动修改 mysql.user 等系统表后才必须执行。
但它的问题在于:
- 强制重载整张权限表,在高并发实例中可能引发短暂锁表
- 掩盖了真正该检查的点:你是否真的撤对了用户、范围和权限类型
所以优先做的是:SHOW GRANTS FOR 'user'@'host' —— 输出里不再出现你要撤的权限项,才是撤销成功的唯一证据。至于要不要 FLUSH PRIVILEGES,取决于你用的是 MySQL 版本和操作方式,而不是“习惯性补上”。











