不能直接撤销单表DROP权限;REVOKE必须严格匹配GRANT的权限类型、作用范围和层级,如GRANT DELETE ON mydb.users需用REVOKE DELETE ON mydb.users,不支持按对象粒度撤销DDL权限。

MySQL 里用 REVOKE 撤销 DROP 或 DELETE 权限,到底能不能直接干掉?
不能直接“收回某个表的 DROP”,REVOKE 不支持按对象粒度撤销单条 DDL 权限——它只认权限类型 + 作用范围。你给的是数据库级 DROP,撤回来也得是同级;给的是表级 DELETE,撤时必须明确写表名。
REVOKE 必须匹配当初 GRANT 的范围和层级
权限不是“开关式”独立存在,而是绑定在 ON database.table 这种上下文里的。当初用 GRANT DELETE ON mydb.users TO 'u1'@'%' 给的,现在就得写 REVOKE DELETE ON mydb.users FROM 'u1'@'%' 才生效;如果当初是 GRANT DROP ON *.*,那只能 REVOKE DROP ON *.*,没法只撤某个库的 DROP。
- 不写
ON子句会报错:ERROR 1141 (42000): There is no such grant defined for user 'u1'@'%' on host '%' - 库名或表名大小写敏感(取决于
lower_case_table_names设置),REVOKE DELETE ON MyDB.Users和mydb.users可能不匹配 - 通配符
*不能混用:不能REVOKE DELETE ON mydb.* FROM ...去撤销GRANT DELETE ON mydb.t1,必须精确到表或用同级通配
撤销 DROP 权限后,用户还能删表吗?要看有没有其他权限路径
DROP 权限只是删表的其中一种方式。如果用户还拥有 ALTER + CREATE(可先 RENAME 再重建),或者有 SUPER / SYSTEM_VARIABLES_ADMIN(能关 sql_log_bin 绕过 binlog 约束),甚至通过存储过程间接执行 DROP,那单纯 REVOKE DROP 就形同虚设。
- 检查是否残留高危权限:
SELECT * FROM mysql.role_edges WHERE TO_HOST = '%' AND TO_USER = 'u1'; - 确认无代理权限:
SELECT * FROM mysql.proxies_priv WHERE Host = '%' AND User = 'u1'; -
DROP被撤后,TRUNCATE TABLE仍可能成功——它依赖DELETE+DROP,但部分版本只要求DELETE
PostgreSQL 和 SQL Server 怎么办?语法和逻辑完全不同
MySQL 的 REVOKE 是基于 GRANT 语句逆向操作;PostgreSQL 必须用 REVOKE ... ON TABLE 显式指定对象,且默认不级联,DROP 类权限实际对应 CREATE(在 schema 上)或 USAGE + CREATE 组合;SQL Server 则靠 REVOKE CONTROL ON OBJECT::t1 FROM u1 这类细粒度控制,DROP 行为本质是 CONTROL 权限的一部分。
- PostgreSQL 示例:
REVOKE DROP ON SCHEMA public FROM u1;❌ 错误,应改用REVOKE CREATE ON SCHEMA public FROM u1; - SQL Server 示例:
REVOKE ALTER ON OBJECT::users FROM u1;—— 因为DROP TABLE隐含在ALTER权限里 - 所有系统都不支持 “撤回某次 GRANT 的某个子权限”,比如从
GRANT SELECT, INSERT, DELETE中只撤DELETE,必须全量REVOKE再重GRANT剩下的
真正难的不是写对那条 REVOKE 语句,而是搞清权限当初是怎么一层层叠加上去的——角色、代理、嵌套组、动态 SQL、存储过程定义者权限……漏掉任意一环,权限就还在那儿。

















