最有效方式是启用skip-name-resolve=ON并重启MySQL,但必须将mysql.user表中所有域名Host改为IP或%并执行FLUSH PRIVILEGES,否则因权限匹配失败全部报Access denied;验证方法包括停DNS服务后秒连、IPv6回环快速响应、SHOW PROCESSLIST中Host显IP且状态卡Connecting。

直接关掉 skip_name_resolve 是最有效的解决方式,但必须同步修复权限表中所有非 IP 的 Host 值,否则会全部报 Access denied。
怎么快速确认是反向解析卡住的?
别靠日志猜,用两个命令秒判:
- 停本地 DNS 服务:
sudo systemctl stop systemd-resolved,再执行mysql -h 127.0.0.1 -u root -p—— 如果从卡顿变秒连,基本锁定 - 换 IPv6 回环测试:
mysql -h ::1 -u root -p—— 若 IPv4 慢、IPv6 立即响应,说明gethostbyaddr()在 IPv4 路径上阻塞 - 登录后查状态:
SELECT @@skip_name_resolve;返回0表示未跳过;SHOW PROCESSLIST;中新连接长期卡在Connecting状态且Host列显示 IP(如10.0.2.5:52183)而非主机名,也是典型信号
如何正确启用 skip-name-resolve?
这个参数只在 MySQL 启动时读取,写错位置或不重启等于白配:
- 必须加在配置文件的
[mysqld]段下,常见路径:/etc/my.cnf、/etc/mysql/mysql.conf.d/mysqld.cnf(Ubuntu/Debian)、my.ini(Windows) - 写法严格:只接受
skip-name-resolve = ON或skip-name-resolve(无值也生效),skip_name_resolve是无效拼写 - 必须重启服务:
sudo systemctl restart mysql(reload不生效) - 验证是否真正生效:
mysql -e "SHOW VARIABLES LIKE 'skip_name_resolve';"返回ON才算成功 - 注意覆盖逻辑:Ubuntu/Debian 下
!includedir /etc/mysql/conf.d/可能覆盖主配置,先运行mysqld --verbose --help | grep "Default options"确认最终加载路径
开了 skip-name-resolve 为什么连不上了?
这不是故障,是设计行为:MySQL 彻底跳过反向解析后,mysql.user 表里的 Host 字段只能字面匹配 IP 或 %,所有域名授权全部失效。
- 典型表现:
GRANT ... TO 'app'@'web01.example.com'存在,但用mysql -h 192.168.1.100连就报Access denied for user 'app'@'192.168.1.100' - 检查问题账号:
SELECT User, Host FROM mysql.user WHERE Host NOT IN ('%', 'localhost', '127.0.0.1', '::1') AND Host NOT REGEXP '^\d+\.\d+\.\d+\.\d+$'; - 修复方式(二选一):
– 逐条更新:UPDATE mysql.user SET Host = '192.168.1.100' WHERE User = 'app' AND Host = 'web01.example.com';
– 或改用网段:UPDATE mysql.user SET Host = '192.168.1.%' WHERE User = 'app' AND Host = 'web01.example.com'; - 最后必须执行:
FLUSH PRIVILEGES;
云环境和动态 IP 场景要特别小心
Kubernetes Pod、Serverless、弹性伸缩等场景下,客户端 IP 频繁变化,硬写具体 IP 不可持续。此时开 skip-name-resolve 反而增加维护成本——你得不断同步权限表,或者退而求其次用 '%' ,但又违背最小权限原则。这种情况下,更稳妥的做法是:在内网 DNS 或 /etc/hosts 中补全 PTR 记录,或调小 glibc 的 DNS 超时(options timeout:1 attempts:2),而不是强行跳过解析。


















