直接撤销 DROP 和 DELETE 权限必须严格匹配原始 GRANT 的数据库名、表名和 host,否则无效;撤销后需新连接验证,旧连接仍保留权限。

直接撤销 DROP 和 DELETE 权限是可行的,但必须和当初 GRANT 时的范围(数据库/表名、host)完全一致,否则语句执行成功却无效。
REVOKE DROP 必须写全数据库名和表名
MySQL 不支持“只撤某张表的 DROP 权限”这种模糊操作。哪怕你只想撤 mydb.logs 的 DROP,也必须显式写出完整路径,不能省略数据库名或用通配符替代。
-
REVOKE DROP ON mydb.logs FROM 'app'@'10.0.2.%'✅ 合法且有效(前提是当初就是这么授的权) -
REVOKE DROP ON logs FROM 'app'@'10.0.2.%'❌ 报 ERROR 1141 或静默失败 -
REVOKE DROP ON mydb.* FROM 'app'@'10.0.2.%'❌ 即使用户确实有mydb.*的 DROP,但如果当初授的是mydb.logs,这条就无效 - 不支持
REVOKE DROP ON *.*来覆盖所有表——它只影响全局级授权,对库/表级权限无作用
REVOKE DELETE 必须匹配原始 ON 范围
DELETE 权限的撤销粒度和 GRANT 严格绑定。MySQL 不会自动推导或合并权限范围,ON 子句错一个字符,就等于没撤。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 查原始授权:先运行
SHOW GRANTS FOR 'app'@'10.0.2.%',找到含DELETE的那一行,复制整个ON ...部分 - 照抄改写:把
TO 'app'@'10.0.2.%'改成FROM 'app'@'10.0.2.%',其余不动 - 别贪快写
REVOKE DELETE ON *.*—— 它对myapp.users上的 DELETE 没任何影响 - 如果用户在多个 host 有记录(比如
'app'@'localhost'和'app'@'10.0.2.%'),必须分别执行对应语句
撤销后权限不立即生效,连接复用是最大盲区
执行 REVOKE 后,已建立的连接(包括连接池里的长连接)仍保有旧权限,直到断开重连。这不是 bug,是 MySQL 的设计机制。
-
FLUSH PRIVILEGES只刷新内存权限缓存,不影响活跃连接;它不是万能触发器 - 验证是否真生效,唯一可靠方式是用新连接测试:
mysql -u app -h db-host -p -e "DELETE FROM myapp.users LIMIT 1" - 生产环境需配合应用侧滚动重启连接池,或设置较短的连接空闲超时(如
wait_timeout) - 不要依赖
SHOW GRANTS的输出判断当前连接是否受限——它只反映账号配置,不反映连接上下文
最容易被忽略的一点:同一个用户名在不同 host 下是独立账户,权限互不干扰;而 DROP 权限只能按表精确撤销,无法“批量清理某库下所有表的 DROP”,必须逐表确认并执行。

















