Unknown MySQL server host 错误源于操作系统或glibc的DNS解析缓存未更新,非MySQL自身问题;应改用IP直连、检查nsswitch.conf、刷新nscd/systemd-resolved缓存,并理解skip_name_resolve仅影响服务端反向解析。

MySQL 连接报 Unknown MySQL server host 错误
这是 DNS 变更后最典型的症状:MySQL 客户端(包括 mysql 命令、应用连接池、甚至 mysqld 自身的复制配置)在解析主机名时失败。根本原因不是 MySQL 本身缓存 DNS,而是操作系统或底层 C 库(glibc)的 DNS 解析行为——它默认不主动刷新,且部分场景下会复用早期解析结果。
- 常见于容器重启、K8s Pod IP 变更、RDS 实例切换、或 DNS 记录 TTL 过长后手动更新但未生效
-
ping或nslookup能通 ≠ MySQL 能连通:MySQL 客户端调用的是getaddrinfo(),行为可能和 shell 工具不同(尤其在 IPv6 / 多地址返回时) - 不要依赖
flush hosts:这个命令只清空 MySQL 内部的 Host Cache(针对反向 DNS 查找失败的 IP),对正向主机名解析无效
客户端连接时强制跳过 DNS 解析(推荐方案)
最稳妥的做法是让客户端根本不走 DNS——直接用 IP 地址连接。这对生产环境尤其重要,避免 DNS 故障传导到数据库层。
- 应用配置里把
host参数从域名(如db-prod.example.com)换成解析后的 IP(如10.20.30.40) - 使用
mysql命令行时,显式指定 IP:mysql -h 10.20.30.40 -u user -p - 如果必须用域名(比如多可用区自动路由),可在连接字符串加
?allowPublicKeyRetrieval=true&useSSL=false等参数,但不解决 DNS 问题;真正要改的是底层网络层 - Java 应用若用 HikariCP,注意
hostname配置项不能是域名,除非你确认 JVM 启动时已加载最新 DNS 缓存(实际很难保证)
服务端 skip_name_resolve 的真实作用
这个配置常被误解为“关闭 DNS”,其实它只影响 MySQL 服务端对**客户端 IP 的反向解析**(即收到连接后,要不要把 10.20.30.40 反查成 web-01.internal)。它完全不干预客户端发起的正向解析(db-prod.example.com → IP)。
- 开启后,
GRANT语句中所有user@host的host部分必须是 IP 或%,不能再写域名(否则权限不生效) - 开启后,
processlist和慢日志里的host列显示为 IP,而非域名,排查时少一层转换 - 修改需重启
mysqld,且仅对新连接生效;已有连接不受影响 - 设置方式:
SET GLOBAL skip_name_resolve = ON;(临时)或在my.cnf的[mysqld]段加skip_name_resolve = 1
/etc/nsswitch.conf 和 glibc 的缓存陷阱
Linux 下,getaddrinfo() 行为受 /etc/nsswitch.conf 控制。如果该文件里 hosts: 行包含 dns,就走系统 DNS;若还配了 mdns4_minimal 或 resolve,可能引入额外延迟或失败路径。
- 检查当前解析顺序:
grep '^hosts:' /etc/nsswitch.conf,典型应为hosts: files dns - glibc 不自带 DNS 缓存,但很多发行版会预装
nscd或systemd-resolved;若启用,需手动刷新:sudo systemctl restart nscd或sudo systemd-resolve --flush-caches - 容器内尤其要注意:基础镜像可能没装
nscd,但/etc/resolv.conf被覆盖成 K8s CoreDNS 地址,此时 DNS 变更依赖 CoreDNS 自身 TTL 和刷新机制 - 验证是否真由 DNS 引起:在客户端机器上运行
strace -e trace=getaddrinfo mysql -h your-hostname -e 'SELECT 1' 2>&1 | grep -A2 getaddrinfo,看返回的 IP 是否正确










