最可靠白名单是用CREATE USER指定IP,因MySQL无全局白名单开关,Host字段即账号身份一部分;需确保GRANT Host一致、删掉'%'账号、配合防火墙及注意8.0认证插件兼容性。

直接用 CREATE USER 指定 IP,才是最可靠白名单
MySQL 本身没有“白名单配置项”这种全局开关,所谓白名单,本质是靠用户账号的 Host 字段控制——它不是附加规则,而是账号身份的一部分。你创建 'user'@'192.168.1.50',就等于声明“这个账号只接受来自 192.168.1.50 的连接”,其他 IP 即使密码正确也连不上。
- 不要试图在
my.cnf里加ip-whitelist=...—— 这不是 MySQL 官方支持的配置项,某些第三方插件或云厂商定制版可能有,但标准 MySQL(包括 8.0/5.7)根本不识别该参数,写了也无效 -
GRANT必须和CREATE USER的Host完全一致,比如CREATE USER 'app'@'10.0.2.%'后,必须用GRANT ... TO 'app'@'10.0.2.%',写成@'%'或@'10.0.2.100'都会失败 - 子网通配符只支持
%和_:'app'@'10.0.2.%'允许整个 /24 网段,'app'@'10.0.2.1__'(两个下划线)可匹配 10.0.2.100–10.0.2.199,但不支持 CIDR 格式如10.0.2.0/24
删掉 'user'@'%' 是关键一步,否则白名单形同虚设
很多环境里已有 root 或应用账号被建成了 'admin'@'%',这相当于在门上装了指纹锁却把钥匙扔在门口——只要这个账号存在,任何能连到 3306 端口的机器都能试密码暴力破解。白名单生效的前提,是确保没有更宽泛的 Host 覆盖它。
- 先查清楚:执行
SELECT User, Host FROM mysql.user;,重点看有没有带%或localhost以外通配符的账号 - 删除危险账号:用
DROP USER 'olduser'@'%';,注意不能只用DROP USER 'olduser';(MySQL 8.0+ 会报错,必须带完整Host) - 别依赖
UPDATE mysql.user SET Host='192.168.1.100' WHERE User='olduser'—— 直接改表不刷新权限缓存,且可能破坏密码哈希字段,风险远高于重建账号
防火墙 + MySQL 双层限制,缺一不可
MySQL 层的 Host 控制只在认证阶段起作用;如果攻击者能发 TCP 包到 3306 端口,就可能触发协议解析漏洞、耗尽连接数或打日志绕过。所以操作系统防火墙是必要兜底。
- Linux 上用
ufw最简明:ufw allow from 192.168.1.100 to any port 3306,然后ufw enable;别漏掉ufw deny 3306关闭默认放行 - 云服务器(如腾讯云、阿里云)必须同步配置安全组——数据库实例的公网/内网入口规则,比本地防火墙优先级更高,这里没放开,本地
ufw再严也没用 - 避免误伤:测试时用
telnet your-db-ip 3306看端口是否可达,而不是只测mysql -h登录,前者能区分是网络层拦截还是 MySQL 层拒绝
MySQL 8.0+ 的认证插件差异,容易导致连接失败
MySQL 8.0 默认用 caching_sha2_password 插件,但老客户端(如某些 Python 2.x 驱动、旧版 Navicat)不支持,会报 Authentication plugin 'caching_sha2_password' cannot be loaded。这时不能简单降级插件,而要显式指定。
- 创建用户时明确插件:
CREATE USER 'api'@'192.168.1.200' IDENTIFIED WITH mysql_native_password BY 'pwd123'; - 已有用户可修改:
ALTER USER 'api'@'192.168.1.200' IDENTIFIED WITH mysql_native_password BY 'pwd123'; - 切勿全局改
default_authentication_plugin—— 可能影响 root 或监控账号,最小化改动只针对白名单用户
Host 值必须和客户端发起连接时 MySQL 看到的源 IP 完全一致。NAT、代理、K8s Service ClusterIP 都可能导致你以为的“192.168.1.100”在 MySQL 日志里显示为“10.244.1.5”或“127.0.0.1”,这时候就得按真实记录的 IP 来建账号。










