mysql 8.0 无独立ip白名单开关,实为三层协同控制:操作系统防火墙(第一道物理门禁)、用户host字段匹配(第二道认证层限制)、mysql_firewall插件(第三道sql行为过滤),任一层缺失或范围不一致均导致防护失效。

直接上结论:MySQL 8.0 本身不提供“IP白名单”这个独立功能开关,所谓白名单其实是三层叠加控制的结果——操作系统防火墙、MySQL用户账号的host字段限制、以及可选的mysql_firewall插件。只改其中一层,等于门禁系统只装了半扇门。
为什么CREATE USER 'app'@'192.168.1.100'不是万能的
很多人以为只要把用户 host 写死成具体 IP,就等于加了白名单。但现实是:
- 这个限制只在 MySQL 认证阶段生效,连接请求仍会抵达 MySQL 的 3306 端口,消耗连接数、触发日志、可能被暴力扫描盯上
- 如果应用配置错误或开发环境混用(比如
'app'@'%'残留),这条限制就形同虚设 - MySQL 不校验客户端真实出口 IP(例如经 NAT 或代理转发后),
host值仅反映连接发起时 TCP 包里的源地址,不可信
所以它只是第二道防线,不能替代网络层拦截。
必须配操作系统防火墙:用ufw或firewalld堵住 3306 入口
这是真正意义上的第一道物理门禁。以 Ubuntu + ufw 为例:
sudo ufw allow from 192.168.1.100 to any port 3306 sudo ufw allow from 10.0.2.0/24 to any port 3306 sudo ufw deny 3306 sudo ufw enable
关键点:
- 规则顺序很重要:
allow必须在deny之前;否则全被拦掉 - 云服务器还要同步配置安全组(如阿里云/腾讯云控制台),防火墙和安全组是“与”关系,任一拒绝即不通
- 别忘了给自己留调试通道,比如加一条
sudo ufw allow from <your-ip> to any port 22</your-ip>,避免锁死 SSH
启用mysql_firewall插件做连接后的行为白名单
这是 MySQL 8.0+ 提供的细粒度控制,适合防止 SQL 注入绕过或误执行高危语句,但它不控制 IP,而是控制“谁连上来之后能干什么”:
INSTALL PLUGIN mysql_firewall SONAME 'mysql_firewall.so'; SET GLOBAL mysql_firewall_mode = ON;
使用前提:
- 必须先有明确的用户账号(如
'app'@'192.168.1.100'),插件按用户维度管理规则 - 需用
mysql_firewall_users表手动加载允许的语句模式,不是自动学习 - 它不替代
host限制或防火墙,而是补充:即使 IP 和账号都对,SQL 也可能被拦截
典型误操作:开了插件但没调用 CALL mysql_firewall.flush_hosts(),规则不生效。
最容易被忽略的是三层协同失效场景:比如防火墙放行了整个办公网段(192.168.1.0/24),但 MySQL 用户却只授权给单个 IP('app'@'192.168.1.100')——这时来自 192.168.1.101 的连接会被 MySQL 拒绝,但请求已穿透网络层,白白占用资源。真要严密,三层的范围必须对齐,且优先级从外到内依次收紧。











