mysql如何排查DNS解析慢导致的连接延迟_mysql skip-name-resolve应用

4次阅读

mysql连接卡在“connecting to localhost…”是dns反向解析阻塞所致;需在服务端my.cnf的[mysqld]段启用skip-name-resolve并重启,此时host列将只显示ip,但域名账号权限会失效,且k8s等依赖dns的服务场景需谨慎评估。

mysql如何排查DNS解析慢导致的连接延迟_mysql skip-name-resolve应用

MySQL 连接卡在“Connecting to localhost…” 阶段

这是典型的 DNS 反向解析阻塞表现。MySQL 客户端或服务端在建立连接时,会尝试对客户端 IP 做 gethostbyaddr() 反查主机名——哪怕你只用 127.0.0.1 连,只要服务端没关解析,它仍可能去查本地 /etc/hosts 或 DNS 服务器。

常见错误现象:
mysql -h 127.0.0.1 -u root -p 要等 5–10 秒才进命令行
SHOW PROCESSLIST; 里看到大量 Connecting 状态的线程Host 列显示的是 IP(如 192.168.1.100:54321),但状态长期不更新
• 错误日志里没有报错,但 slow_log 或监控发现连接耗时集中在“初始化阶段”

  • 确认是否真由 DNS 引起:临时停掉本机 DNS 服务(如 systemctl stop systemd-resolved)再连一次;或改用 mysql -h ::1(IPv6 回环)测试——若 IPv6 快很多,基本锁定是 IPv4 反解问题
  • 不要依赖客户端加 --skip-name-resolve:这个参数只影响客户端行为,对服务端无用;真正要改的是 MySQL 服务端配置
  • 生产环境别靠改 /etc/hosts 硬凑映射:IP 多、容器动态分配时不可维护,且无法覆盖公网 IP 场景

启用 skip-name-resolve 的正确位置和副作用

这个配置项必须加在 MySQL 服务端的 my.cnf(通常是 /etc/my.cnf/etc/mysql/mysql.conf.d/mysqld.cnf)的 [mysqld] 段下,不是客户端配置文件。

加完后需重启 mysqld 进程生效,仅 reload 不行。

  • skip-name-resolve 生效后,MySQL 将跳过所有客户端 IP 的反向 DNS 解析,user@host 权限判断中的 host 部分只能写 IP 或 %,不能再写域名(如 'app'@'web01.example.com' 会失效)
  • 已存在的基于域名的账号不会自动转换,需要手动用 UPDATE mysql.user SET Host='10.0.2.5' WHERE User='app' AND Host='web01.example.com'; FLUSH PRIVILEGES; 修复
  • 如果应用连接串里用了 hostname(如 host=database-prod),DNS 解析慢的问题其实还在客户端侧,skip-name-resolve 并不解决这个——那是你 DNS client 配置或网络的问题

验证 DNS 解析是否真被绕过

最直接的办法是看 PROCESSLISTHost 列是否始终显示 IP,而不是主机名。

执行:
select ID, USER, HOST, COMMAND, TIME, STATE FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep';

  • 如果 HOST 列全是 IP(如 10.0.3.12:49231),说明 skip-name-resolve 已生效
  • 如果仍有 web01.example.com:38422 这类带域名的值,说明配置没生效,或 mysqld 没重启,或你连的是另一个实例(比如 docker 容器里跑的 MySQL,配置改的是宿主机)
  • 补充验证:在服务端机器上执行 strace -e trace=gethostbyaddr,getaddrinfo -p $(pgrep mysqld) -s 99 2>&1 | grep -i "name|host",正常情况下不应看到解析系统调用被触发

为什么有些场景不能直接开 skip-name-resolve

不是所有环境都适合一刀切关闭 DNS 解析。关键矛盾点在于权限模型和运维习惯。

  • 某些老系统依赖 'reporter'@'bi-server.internal' 这类基于 FQDN 的账号做隔离,关掉后要么批量改账号,要么暴露权限管理漏洞
  • kubernetes 环境中,Pod IP 是动态的,但 Service DNS 名(如 mysql.default.svc.cluster.local)稳定——此时服务端开 skip-name-resolve 反而让客户端连不上,因为客户端解析出的 IP 会被服务端拒绝(因 Host 匹配不到预设域名)
  • 部分审计合规要求记录来源主机名而非 IP,关掉后日志和审计字段丢失可追溯性,需额外补方案(如用代理层透传 X-Real-IP + 应用层写入)

真正难的从来不是加一行配置,而是理清“谁在解析”“为什么需要解析”“解析失败后谁兜底”。线上动这个开关前,先抓包看三次握手后的第一个 TCP payload 是什么,比盲改配置靠谱得多。

text=ZqhQzanResources