根本原因是MySQL 5.7默认开启DNS反向解析,服务端对客户端IP调用gethostbyaddr()查询hostname,若无PTR记录或DNS超时(云/内网常见),会卡1–5秒;启用skip_name_resolve=ON可解决,但需同步将授权语句中的域名改为IP或通配符。

为什么 SHOW GRANTS 或新连接卡住几秒?
根本原因不是权限表本身慢,而是 MySQL 5.7 默认开启 DNS 反向解析:每次新连接进来,服务端会调用 gethostbyaddr() 把客户端 IP 查成 hostname。如果该 IP 没配 PTR 记录,或 DNS 服务器响应超时(常见于云环境、内网无 DNS 服务),就会卡住 1–5 秒——你看到的“验证慢”,八成是卡在这步。
验证方式很直接:
- 在 MySQL 服务端执行
SELECT @@skip_name_resolve;,返回0就确认没跳过 - 用真实 IP 连接复现:
mysql -h 192.168.1.100 -u testuser -p(别用localhost,它走 socket,不触发解析) - 抓包看 DNS 请求:
tcpdump -i any port 53,连一次就看到一堆 UDP 查询,基本坐实
怎么安全启用 skip_name_resolve = ON?
这不是加个配置重启就完事。MySQL 5.7 启用后,所有带主机名的授权都会失效,比如 'app'@'web01.example.com' 会匹配失败,必须改用 IP 或通配符。
操作前先检查现有授权:
- 查出所有含域名的用户:
SELECT User, Host FROM mysql.user WHERE Host NOT IN ('%', '127.0.0.1', '::1') AND Host NOT LIKE '%.%'; - 把域名改成对应 IP 段,例如
'app'@'10.20.30.%';若无法确定范围,暂用'app'@'%'(生产慎用) - 编辑配置文件(
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf),在[mysqld]下加:skip_name_resolve = ON - 必须重启 mysqld:
systemctl restart mysql(只重载配置不生效)
FLUSH PRIVILEGES 后还是慢?线程缓存没清干净
MySQL 权限有两层缓存:全局级和线程级。执行 FLUSH PRIVILEGES 只刷新全局缓存,但已建立的连接仍用着旧的线程快照,直到断开或显式重载。
所以你会遇到:
免费 DNS 与邮件安全分析(IntoDNS.ai):包括 DNSSEC、SPF、DKIM、DMARC、MTA-STS、BIMI、SMTP STARTTLS、FCrDNS、黑名单、发件人要求及报告。
- 新建连接立刻变快(因为走新配置)
- 老连接仍卡顿、
SHOW GRANTS还慢 - 应用里连接池长期存活,问题持续存在
临时解法是杀掉旧连接:KILL <thread_id>;</thread_id>,或等连接自然超时断开(由 wait_timeout 控制)。长期方案是让应用支持连接健康检测与自动重建。
授权语句写错导致索引失效,比 DNS 还难排查
即使关了 DNS,SHOW GRANTS FOR 'user' 或权限校验仍可能慢——根源在 mysql.user 表查询没走索引。
MySQL 5.7+ 的 mysql.user 主键是 (Host, User),但很多人写查询时只带 User:
-
SELECT * FROM mysql.user WHERE User = 'app';→ 全表扫描 -
SELECT * FROM mysql.user WHERE Host = '192.168.1.%' AND User = 'app';→ 走主键索引 - Host 字段用了
'%.example.com'这种通配符开头 → 索引完全失效,且无法优化
补救动作:
- 执行
ANALYZE TABLE mysql.user;更新统计信息(批量增删用户后必做) - 永远用
GRANT/CREATE USER修改权限,别直接UPDATE mysql.user(后者不刷新内存缓存) - Host 值尽量用具体 IP 或
'10.20.30.%',避免'%myapp'类前缀模糊匹配
真正卡住的点往往不在配置开关本身,而在于授权粒度和缓存层级的耦合——改完 skip_name_resolve,顺手扫一遍 mysql.user 里的 Host 写法,比反复重启更省时间。

















