主流数据库不支持主机名白名单,只认IP或CIDR;所谓主机名实为客户端DNS解析后匹配IP,服务端默认不反查DNS;生产环境必须用真实IP或子网段,云上优先内网IP。
数据库连接层的白名单 ≠ 主机名白名单
直接说结论:mysql、postgresql、polardb 等主流数据库不支持用“主机名”(如 app-server-01.internal)配置白名单——只认 ip 或 cidr 段。所谓“主机名白名单”,实际是 dns 解析后匹配 a/aaaa 记录的 ip,且解析发生在客户端或中间件侧,数据库服务端本身不做反向 dns 查询(除非显式启用并配置了 skip_name_resolve=off,但强烈不建议)。
常见错误现象:
• 在控制台填了 web01.example.com,结果连不上,日志里报 Host 'xxx.xxx.xxx.xxx' is not allowed to connect
• 本地 ping web01.example.com 能通,但数据库拒绝连接
• 同一个主机名在不同网络环境解析出不同 IP,白名单失效
- 生产环境必须用真实 IP 或子网段(如
10.17.35.68或192.168.1.0/24),不能依赖 DNS - 如果业务部署在云上(如阿里云 ECS、腾讯云 CVM),优先使用内网 IP 段,避免走公网 NAT 导致源 IP 变成网关地址
- 开启
skip_name_resolve=OFF虽然能让 MySQL 尝试反查 hostname,但会显著拖慢连接建立(每次连接都做 DNS 查询),且不可靠——DNS 故障即全挂
云数据库白名单设置实操要点(以阿里云 PolarDB/RDS 为例)
云厂商控制台里的“IP 白名单”本质是安全组 + 数据库访问控制双层过滤,不是数据库原生命令。你填的 IP 列表最终会转化为底层防火墙规则和数据库授权语句。
- 默认分组只含
127.0.0.1,意味着“任何外部 IP 都连不上”,这是安全基线,别手滑删掉 - 添加多个 IP 时,用英文逗号分隔,不要加空格:正确是
10.17.12.158,10.17.35.68,192.168.0.0/24;错写成10.17.12.158, 10.17.35.68会导致第二个 IP 被忽略 - 如果你用 NAT 网关或 SLB 访问数据库,白名单要填的是**出口 IP**(即 NAT 网关的 EIP 或 SLB 的私网 IP),不是源 ECS 的内网 IP
- 每个白名单分组最多 1000 个条目,超限时需新建分组——别堆在一个分组里硬塞
本地 MySQL 手动授权时的 IP 写法陷阱
如果你有 root 权限直连数据库执行 GRANT,注意 MySQL 用户账号格式是 'user'@'host',这里的 host 是匹配规则,不是 DNS 名。
-
'app'@'10.17.35.68':仅允许该单 IP -
'app'@'10.17.%.%':支持通配符,但只对 IP 有效,%不代表子网,而是字符匹配(等价于10.17.*.*) -
'app'@'%':危险!允许任意 IP,包括公网 —— 即便云平台白名单已限制,也不该在账号层放得这么宽 -
'app'@'localhost'和'app'@'127.0.0.1'是两个不同账号,前者走 Unix socket,后者走 TCP,别混淆
执行完记得 FLUSH PRIVILEGES;,否则授权不生效。
为什么“IP 白名单”有时像没起作用?
最常被忽略的其实是网络链路中的隐性 IP 转换。白名单检查发生在数据库接受 TCP 连接握手时,但如果你的请求经过了代理、Nginx、Zuul 或 Kubernetes Service,源 IP 很可能已被覆盖。
- HTTP 层代理(如 Nginx)需透传真实 IP:配置
proxy_set_header X-Real-IP $remote_addr;,但这对数据库直连无效 - 数据库连接池(如 HikariCP)或 ORM(如 SQLAlchemy)不会自动读取 HTTP 头,它们看到的就是 socket 对端 IP
- 云厂商的“高安全白名单模式”会强制校验 TLS 客户端证书 + IP 双因子,此时光填 IP 不够,还得配证书信任链
- Elasticsearch 的
xpack.security.http.filter.allow是收费功能,免费版不生效——别白折腾配置
真要靠主机名控制访问,得在应用网关或 Service Mesh 层做(比如 Istio 的 AuthorizationPolicy),而不是指望数据库自己解析 hostname。










