MySQL 解除 Host is blocked
摘要
- 远程客户端报
Host is blocked(错误号 1129)时,先查出是哪台主机,再执行TRUNCATE TABLE performance_schema.host_cache解除封锁,并说明max_connect_errors怎么调 - 本文按 MySQL 8.4。同一条
TRUNCATE在 8.0 上可用。FLUSH HOSTS自 8.0.23 起弃用,8.4 已删除 - 官方文档:DNS Lookups and the Host Cache、The host_cache Table。变量持久化见 MySql--系统变量;配置文件里的
max_connect_errors见 MySql单节点、主从、双主的构建方法、MySql8.4单节点、主从、双主的构建方法
报错代表什么
客户端连不上时,服务器返回错误号 1129,原文是:
1 | Host 'host_name' is blocked because of many connection errors. |
有的客户端会合成一行,中间用分号。解除封锁的语句是:
1 | TRUNCATE TABLE performance_schema.host_cache; |
MySQL 在内存里维护 host_cache,做两件事:缓存客户端 IP 到主机名的 DNS 结果;记录连接过程中的错误。某个 IP 的协议握手连续失败,次数达到全局变量 max_connect_errors(默认 100)之后,服务器拒绝这个 IP 后续新建立的 TCP 连接。
这张缓存只用于非本机的 TCP 连接。走 127.0.0.1、::1、Unix socket、命名管道或共享内存的连接不进缓存,也不会被这条规则封锁。远程 IP 被封之后,仍可以在数据库本机用 socket 连上去执行上面的 TRUNCATE。
网络抖动,或连接池在握手阶段大量失败重连时,共用一个出口 IP 的整组应用会一起被拒。密码错误记在 COUNT_AUTHENTICATION_ERRORS,不参与和 max_connect_errors 的比较。
达到阈值之前,这个 IP 一旦有一次连接成功,连续失败计数会清成 0。已经封上之后,后来的连接会被拒绝,计数不会自己回到 0。并发握手时,计数可以一次超过阈值:连接开始时还没到阈值的那几条仍可能成功,开始时已经到阈值的新连接才会被拒。
先查出是哪些主机
清空之前先查。下面这条语句只读缓存,不会解封。
1 | -- SUM_CONNECT_ERRORS 大于 0:有过计入阈值的握手错误 |
查不到行,或提示表不存在时,先看 Performance Schema 是否打开,以及当前账号有没有这张表的 SELECT 权限:
1 | SHOW VARIABLES LIKE 'performance_schema'; |
performance_schema 为 OFF 时,performance_schema.host_cache 不存在,后面的 TRUNCATE 也会失败。8.0 和 8.4 默认是 ON。
| 列 | 作用 |
|---|---|
IP |
客户端 IP |
HOST |
该 IP 解析出的主机名,解析失败时为 NULL |
SUM_CONNECT_ERRORS |
计入封锁阈值的握手错误次数,只统计 HOST_VALIDATED = YES 的主机 |
COUNT_HANDSHAKE_ERRORS |
协议层握手错误次数 |
COUNT_HOST_BLOCKED_ERRORS |
因已经越过阈值而被拒绝的连接次数 |
COUNT_AUTHENTICATION_ERRORS |
认证失败次数,不参与和 max_connect_errors 的比较 |
列很多,单台主机用 \G 竖排看。下面是 max_connect_errors = 1000 时一台已经被封锁的主机:
1 | mysql> SELECT * FROM performance_schema.host_cache WHERE SUM_CONNECT_ERRORS > 0\G |
-
HOST_VALIDATED为YES,主机名已经解析出来。DNS 相关计数都是 0,这次封锁来自握手失败。 -
SUM_CONNECT_ERRORS和COUNT_HANDSHAKE_ERRORS都是 1000,与当时的max_connect_errors相同。这 1000 次都是协议握手中断。 -
COUNT_HOST_BLOCKED_ERRORS为 242。计数到达阈值之后,又有 242 次连接被拒绝。拒绝次数加在这一列,SUM_CONNECT_ERRORS停在 1000。 -
COUNT_AUTHENTICATION_ERRORS以及账号、SSL、连接数配额相关的列都是 0。 -
FIRST_SEEN与FIRST_ERROR_SEEN相同,这条缓存从第一次见到该 IP 起就是错误。LAST_SEEN与LAST_ERROR_SEEN也相同,最近一次活动仍是错误。从2026-11-11 09:57:33到2026-11-12 06:38:33,这台主机一直在失败或被拒绝。时间按当前会话时区显示,见 MySql--时区与地区设置。 -
主机名是这个内网 IP 的 DNS 记录。从
10.10.0.220这台机器发起的连接都记在这一行上。
要让这台主机恢复连接,执行下一节的 TRUNCATE。只把 max_connect_errors 再调大,这 1000 次握手错误和后面的 242 次拒绝还在,封锁不会消失。
缓存满时,最久未使用的条目会被丢掉。丢掉的如果是一台已被封锁的主机,这台主机会因此恢复连接。条目还在、计数仍超过阈值时,要靠下一节的清空。
清空主机缓存
执行账号需要对 performance_schema.host_cache 有 DROP 权限。只有 RELOAD、没有这张表 DROP 的账号会报 DROP command denied。
1 | -- 清空整张主机缓存。被封锁的 IP 可以立刻重试 |
正常结果是 Query OK, 0 rows affected。这张 Performance Schema 表清掉行之后,返回值仍是 0。再用上一节的 SELECT 看:对应 IP 不再出现,或 SUM_CONNECT_ERRORS 为 0,封锁记录已经没了。客户端重新连上,才算服务恢复。查询结果变空,和客户端已经连上,是两件事。
这条语句清的是整张缓存。所有被封锁的主机都会恢复重试,服务器下次连接这些 IP 时要重新做 DNS 解析。
TRUNCATE 报 DROP command denied 时,用 SHOW GRANTS 看当前账号有没有这张表的 DROP,换有权限的账号再执行一次。
其他清空方式
FLUSH HOSTS 从 MySQL 8.0.23 起弃用,MySQL 8.4 已删除。8.4 上执行会报语法错误,用上一节的 TRUNCATE。
8.0.22 及更早版本可以用下面两条,效果和 TRUNCATE 相同。FLUSH HOSTS 需要 RELOAD 权限。
1 | FLUSH HOSTS; |
1 | # 在仍能登录的机器上执行。-h 填 MySQL 服务器地址,命令打到这台服务器上 |
mysqladmin flush-hosts 在 8.4 文档里仍然保留。它需要 performance_schema.host_cache 的 DROP 权限,或 RELOAD 权限。服务器上优先用 TRUNCATE。
运行中把 host_cache_size 改成另一个正数,也会清空缓存并解封,需要 SYSTEM_VARIABLES_ADMIN(旧的 SUPER 也可以)。先 SHOW VARIABLES LIKE 'host_cache_size'; 记下当前值,改完确认客户端能连上之后再设回去。设成 0 会关掉主机缓存:之后不再按 max_connect_errors 封锁主机,每个非本机 TCP 连接都要做一次 DNS 查询。
调大 max_connect_errors
默认值是 100。MySql单节点、主从、双主的构建方法 和 MySql8.4单节点、主从、双主的构建方法 的示例配置里写的也是 100。握手失败很频繁、并且确认 TCP 本身没有持续故障时,可以把阈值调大,减少误封。连接一直在中途被掐断时,调大阈值不能把连接补上。
已经被封锁的主机不会因为阈值变大就自动解开,仍要先做上一节的清空。
先看当前进程里的值:
1 | SHOW VARIABLES LIKE 'max_connect_errors'; |
1 | +--------------------+-------+ |
SET GLOBAL 只改当前进程,重启后回到配置文件里的值,没写进配置文件时回到默认 100。
1 | -- 当前进程立即生效,重启后失效 |
1 | Query OK, 0 rows affected |
改完用同一条 SHOW VARIABLES 确认已经变成 1000。SELECT @@GLOBAL.max_connect_errors; 看到的是同一个全局值。
要重启后仍然是 1000,把下面两行放进实际使用的配置文件的 [mysqld] 段,覆盖原来的 max_connect_errors = 100,然后重启 mysqld。
1 | [mysqld] |
SET GLOBAL 改的是当前进程。配置文件在下次启动时生效。两边都改过,并且重启后再查一次,运行值才会和文件一致。
重启后也要保留这个值、my.cnf 保持原样时,用 SET PERSIST。它写的是数据目录下的 mysqld-auto.cnf。用法见 MySql--系统变量。
1 | SET PERSIST max_connect_errors = 1000; |
做完核对
-
客户端不再报错误号 1129,能建立新连接。
-
SELECT IP, SUM_CONNECT_ERRORS, COUNT_HOST_BLOCKED_ERRORS FROM performance_schema.host_cache WHERE IP = '刚才那个地址';里,这个 IP 不在结果中,或SUM_CONNECT_ERRORS为 0。 -
SHOW VARIABLES LIKE 'max_connect_errors';与打算保留的值一致。改过配置文件的,重启后再查一次。