ProxySQL 是目前最可行的、能在 MySQL 层面动态拦截 DROP 和 DELETE 语句的方案——它不依赖权限系统,也不需要改应用代码,靠规则匹配 + 语义前置判断就能在 SQL 执行前拦住;MySQL 原生权限模型无法细化 DROP 到表级,DELETE 授权后仍无法限制无 WHERE 全表删,且权限只管“能不能”,不管“该不该”,而 ProxySQL 可结合用户、schema、SQL 模式、客户端 IP 等做组合策略拦截。
ProxySQL 是目前最可行的、能在 MySQL 层面动态拦截 DROP 和 DELETE 语句的方案——它不依赖权限系统,也不需要改应用代码,靠规则匹配 + 语义前置判断就能在 SQL 执行前拦住。
为什么不能只靠 MySQL 权限控制 DROP/DELETE
MySQL 原生权限模型里:DROP 是库级权限,无法细化到某张表;DELETE 虽然可按表授权,但一旦开了,就拦不住无 WHERE 条件的全表删。更关键的是:权限控制不了「谁在什么时间、用什么客户端、连哪个 IP」执行了高危语句——它只管“能不能”,不管“该不该”。而 ProxySQL 可以结合用户、schema、SQL 模式、甚至客户端 IP 做组合策略。
mysql-acl 规则如何精准匹配 DROP 和危险 DELETE
ProxySQL 的 mysql-acl 不是简单关键词匹配,它支持正则 + 语义上下文,避免误杀正常业务 SQL(比如 DELETE FROM logs WHERE created_at 是合理操作)。
- 匹配
DROP TABLE必须区分大小写和空格边界:^DROP[[:space:]]+TABLE[[:space:]]+[a-zA-Z0-9_]+,否则会误中ALTER TABLE ... DROP COLUMN - 拦截无
WHERE的DELETE:用^DELETE[[:space:]]+FROM[[:space:]]+[a-zA-Z0-9_]+[[:space:]]*;$,注意结尾分号和空格组合,避开带子查询或 JOIN 的合法 DELETE - 禁止跨 schema 操作:加条件
match_digest = 'DROP' AND username = 'app_user' AND schemaname = 'production',让规则只对生产账号生效 - 所有规则必须设
active = 1且apply = 1,否则只是摆设
配置后必须验证的三个关键点
光写规则不验证,等于没配。ProxySQL 规则生效有隐藏依赖:
- 确认
mysql_servers中后端 MySQL 实例的hostgroup_id与mysql_query_rules中的destination_hostgroup对得上,否则规则根本不会触发 - 执行
SELECT * FROM mysql_query_rules WHERE active=1后,一定要运行LOAD MYSQL QUERY RULES TO RUNTIME,再SAVE MYSQL QUERY RULES TO DISK,缺一步就白忙 - 测试时用真实连接(如
mysql -h 127.0.0.1 -P 6033 -u app_user -p),别用mysql -S /tmp/proxysql.sock—— Unix socket 连接绕过 query rules
真正难的不是写几条正则,而是把规则嵌进你的运维闭环里:每次上线新服务、新增账号、切换主从,都要同步检查 mysql_query_rules 是否仍覆盖当前流量路径。漏掉一次,就可能让一条 DROP TABLE orders 直达主库。