MySQL无“只读+禁止删除”混合权限,需显式回收DROP DATABASE、DROP TABLE、DELETE、TRUNCATE等高危权限,并注意权限作用域一致、刷新生效及连接复用问题。

MySQL账号不能直接设“只读+禁止删除”这种混合权限
MySQL的权限模型里没有“只读但允许删库”或“只读但禁止删库”这种开关。SELECT 和 DROP DATABASE 是完全独立的权限位,必须显式授权或回收——不给 DROP DATABASE 权限,不代表自动获得只读保障,因为用户仍可能用 DROP TABLE、DELETE、TRUNCATE 破坏数据。
真正能防误删的操作是回收具体删除类权限
重点不是“设只读”,而是精准剔除高危操作权限。常见误删来源和对应回收项:
-
DROP DATABASE:删整个库,必须从GRANT列表中移除(哪怕用户有USAGE) -
DROP TABLE:删表,比DROP DATABASE更常被意外触发 -
DELETE和TRUNCATE:清空数据,TRUNCATE还绕过 binlog 记录(取决于引擎) -
ALTER中的DROP COLUMN/DROP INDEX:虽不删数据,但破坏结构,也建议限制
执行示例:
REVOKE DROP DATABASE, DROP TABLE, DELETE, TRUNCATE ON *.* FROM 'app_user'@'%';注意:权限作用域(
*.* vs db_name.*)必须和当初 GRANT 时一致,否则 REVOKE 无效。
账号权限变更后要立即刷新,且注意连接复用问题
权限修改不会实时生效到已存在的连接:
- 必须执行
FLUSH PRIVILEGES;(仅当用INSERT/UPDATE直改mysql表时才需要;用GRANT/REVOKE则自动生效) - 已建立的长连接仍保留旧权限,直到断开重连——这点常被忽略,导致“明明 revoke 了,还能删表”
- 应用若用连接池(如 HikariCP),需重启服务或等待连接超时淘汰,否则新权限不落地
更稳妥的防护得靠外部机制,而非仅靠账号权限
权限控制只是第一道防线,生产环境真正防误删还得叠加其他手段:
- 禁止应用账号直连生产库,统一走代理层(如 ProxySQL)做 SQL 语义拦截,识别并阻断
DROP/TRUNCATE类语句 - 关键库启用
sql_log_bin = 0临时禁用 binlog(仅限维护窗口),避免误操作被复制到从库 - 定期校验
mysql.user表中Drop_priv、Delete_priv字段值,自动化巡检比人工SHOW GRANTS更可靠
最常被忽略的是:权限回收后没验证实际效果。建议用该账号登录后手动执行 DROP DATABASE test_db; 测试是否真报 ERROR 1044 (42000),而不是只看 SHOW GRANTS 输出。










