flush hosts 失效主因是权限不足或根本问题未解决;需用高权限账号执行,或临时重置错误计数,同时排查应用配置、网络中断、dns缓存等诱因,并合理设置max_connect_errors阈值。

FLUSH HOSTS 命令执行失败或没效果怎么办
直接执行 FLUSH HOSTS 报错 ERROR 1227 (42501): Access denied; you need (at least one of) the RELOAD privilege(s) for this operation,说明当前账号没权限。普通应用账号默认没有 RELOAD 权限,不能清 host 缓存。
常见应对方式:
- 换用
root或 DBA 账号登录 MySQL 后再执行FLUSH HOSTS - 在服务器本地用
mysqladmin -uroot -p flush-hosts(需确保该用户有文件系统级访问权限) - Docker 环境下:用
docker exec mysql-db mysqladmin -uroot -p'xxx' flush-hosts,注意密码含特殊字符时建议改用交互式登录 - 如果连高权限账号都不可用,可临时绕过:执行
SET GLOBAL max_connect_errors = 99; SET GLOBAL max_connect_errors = 100;,MySQL 内部会重置对应 host 的错误计数(但仅限当前连接未断开的 session,不保证 100% 可靠)
为什么刚执行 FLUSH HOSTS,马上又报 blocked
这不是命令失效,而是根本问题还在持续发生。只要连接失败动作没停,host cache 里的错误计数就会立刻重新累加。
典型诱因包括:
- 应用配置里写死了错误的密码或用户名,每次启动/重连都触发一次失败
- 连接池(如 HikariCP、Druid)配置了
connection-test-query但 SQL 语法错误,建连后立即执行失败 → 计入错误次数 - 网络中间件(SLB、Nginx TCP proxy、防火墙)主动中断空闲连接,MySQL 收不到 FIN 包,判定为异常断连
- Docker 容器重启后 IP 变更,但应用仍用旧 host cache 中残留的 DNS 名或旧 IP 尝试连接(尤其在
skip-name-resolve=OFF时)
怎么查具体是哪个 IP 被 block 了、当前错几次
MySQL 8.0+ 可直接查 performance_schema.host_cache,但需要 PROCESS 权限;老版本只能间接推断。
推荐组合查询:
- 看阈值:
SHOW VARIABLES LIKE 'max_connect_errors'; - 看当前统计(近似):
SELECT SUBSTRING_INDEX(host,':',1) AS ip, COUNT(*) AS errors FROM information_schema.processlist GROUP BY ip;—— 注意这只是当前活跃连接的 IP 汇总,不是错误计数,仅作参考 - 8.0+ 精确查被 block 的记录:
SELECT HOST, SUM_CONNECT_ERRORS, FIRST_SEEN, LAST_SEEN FROM performance_schema.host_cache WHERE SUM_CONNECT_ERRORS > 0; - 日志里搜:
grep "Host .* is blocked" /var/log/mysql/error.log(路径依实际配置而定)
max_connect_errors 设多少才合理
设太小(比如 10)会让正常网络抖动、DNS 解析慢、SSL 握手延迟等偶发问题直接触发封锁;设太大(比如 10000)又削弱防护能力。
生产环境建议:
- 保持默认 100 通常不够,建议调到
200~500之间 - 必须配合监控:用 Prometheus + mysqld_exporter 抓
mysql_global_status_connection_errors_total和mysql_global_variables_max_connect_errors,设置告警 - 不要只调这个参数就以为万事大吉——它只是兜底机制,不是替代连接健康检查的方案
- 若业务本身连接密集(如 Serverless 场景冷启高频建连),应优先优化连接复用逻辑,而非无脑拉高阈值
真实问题往往藏在“刚恢复就复发”的循环里。别只盯着怎么解封,先抓一次完整连接链路:客户端发起 → 网络路径 → MySQL 认证阶段 → 连接建立完成。漏掉任一环,FLUSH HOSTS 都只是在擦不断渗水的墙。











