MySQL中DROP和ALTER被误执行,根本原因是其权限为库级且无法细化到表,需通过权限隔离、禁用危险配置(如skip-grant-tables、local_infile=ON)及规范操作流程三重防控。

为什么 DROP 和 ALTER 会被普通账号误执行
MySQL 默认的权限模型里,ALTER、DROP、CREATE 这类 DDL 权限一旦授予,就作用于整个库甚至全局。很多团队用一个「开发账号」连所有环境,结果 DROP TABLE users; 在生产库跑完才发现没备份。
真正可控的做法是:不靠人盯,靠权限隔离。重点不是「禁掉高危命令」,而是让这些命令在目标库/表上根本没权限执行。
-
GRANT ALTER ON myapp.* TO 'dev'@'%';→ 允许改myapp库下任意表,但不能碰sys或information_schema -
GRANT DROP ON myapp.users TO 'dev'@'%';→ 只给单表DROP权限(注意:MySQL 不支持对单表授DROP,这句会报错;实际只能控制到库级) - 真正能细粒度限制 DDL 的,只有
CREATE、ALTER、INDEX等——DROP和TRUNCATE始终是库级权限,无法拆到表
如何用 REVOKE 精准回收危险权限
很多人加完权限就不管了,或者用 DROP USER 一删了之,反而导致服务突然中断。更稳妥的是逐项回收,尤其要防「隐式继承」——比如用户有 root@localhost 的权限副本,或通过角色间接获得权限。
执行前先查清当前权限来源:
SHOW GRANTS FOR 'dev'@'%';
然后针对性回收:
-
REVOKE DROP ON *.* FROM 'dev'@'%';→ 回收全局DROP,但不影响其在myapp库的SELECT/INSERT -
REVOKE CREATE, ALTER, INDEX ON myapp.* FROM 'dev'@'%';→ 禁止建表、改结构、加索引,但保留已有表的读写 - 别漏掉
GRANT OPTION:REVOKE GRANT OPTION ON *.* FROM 'dev'@'%';,否则他还能给自己加权限
sql_mode=STRICT_TRANS_TABLES 能防误删吗
不能。这个配置只影响 DML(比如 INSERT 缺字段时报错),对 DROP TABLE、TRUNCATE 这类 DDL 完全无效。有人以为开了严格模式就安全了,结果照样删库跑路。
它真正起作用的场景是:
-
INSERT INTO logs (id) VALUES (NULL);→ 在非严格模式下可能静默转成0,严格模式直接报错 -
UPDATE users SET name='' WHERE id=1;→ 如果name是NOT NULL且无默认值,严格模式拒绝空字符串 - 但它不会拦住
DROP DATABASE test;,哪怕你设了sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES'
生产环境必须关掉的两个 MySQL 配置
这两个开关不开,再细的权限也白搭:
-
skip-grant-tables—— 一旦启用,所有权限检查失效,任何连接都能执行任意命令。排查启动问题时临时开可以,但绝不能留在线上配置文件里 -
local_infile=ON—— 允许客户端用LOAD DATA LOCAL INFILE读取服务器本地任意文件(包括/etc/passwd),配合 SQL 注入可直接读敏感文件。生产必须设为OFF,且在客户端连接参数里也显式禁用:?localInfile=false
权限不是配一次就完事的事。DDL 权限天然粗粒度,DROP 无法按表控制,TRUNCATE 无法被 WHERE 限制,所有「防止手抖」的方案,最终都得靠权限+配置+操作流程三层卡住——少一层,就可能从删表变成删库。


















