该参数累积的是:主机请求服务器失败次数;
该参数控制的是:MySQL服务器是否阻止客户端主机进一步的连接
因为,服务器会假设出了问题(例如,有人试图闯入),并阻止客户端主机进一步连接请求。

这里有几个情况:

  1. 如果累积达到max_connect_errors设置的值,则MySQL服务器会阻止客户端主机的进一步连接,并且会抛出错误
  2. 如果还未达到max_connect_errors设置的值,但是客户端成功连接了MySQL服务器,则主机的错误计数会清零
  3. 如果主机被锁了,可以通过命令解锁(官方文档:https://dev.mysql.com/doc/refman/5.7/en/host-cache.html#host-cache-flushing)

主机被锁的时候,会抛出下面的错误:

解锁的方法:

  1. 提高变量host_cache_size的值 | 需要权限:SUPER
  2. 对performance_schema的表host_cache执行truncate table | 需要对表有权限:DROP
  3. MySQL命令行中执行命令:flush hosts | 需要权限:RELOAD
  4. mysqladmin执行flush-hosts:mysqladmin flush-hosts | 需要权限:RELOAD

下面用几个例子来看看。

先查看数据库中的变量情况:

可以看到,目前 max_connect_errors 设置为了2,也就是说,连接错误达到了2次,客户端的主机的连接就应该会被阻止。

先看看记录客户端连接次数的系统表的状态:

可以看到,该表目前为空。

模拟错误登陆:

可以看到,连接错误。

这个时候,host_cache表的状态:

注意,其中COUNT_AUTHENTICATION_ERRORS已经积累了一次错误。

再次执行一次错误登陆,然后查看host_cache的状态:

可以看到,COUNT_AUTHENTICATION_ERRORS已经累积2次了。

再执行一次错误登陆:

再看看host_cache的状态:

可以看到,COUNT_AUTHENTICATION_ERRORS累积到三次了。
虽然,连接错误,但是并没有触发MySQL服务器对客户端主机的阻止错误。

因为,max_connect_errors指的是:
After max_connect_errors successive connection requests from a host are interrupted without a successful connection
连续请求max_connect_errors,请求最终中断,并且没有得到成功的连接。

因此,要模拟这个错误需要使用:telnet ip_addr 3306
在我的环境中,命令如下:

该命令失败的截图:

连续执行两次,请求失败后,host_cache表中的内容如下:

在上面的查询结果中,注意:SUM_CONNECT_ERRORS,当前已经是2了。

这时候,再用用户名与密码去连接服务器就会被阻止:

这个时候,不论你的密码填写的是正确还是错误,都会被 blocked。


接下来的处理有几种方案。

一、

先从治标不治本的提升 max_connect_errors 参数,开始说:

我们先将 该参数的值 从 2 提升为 5:

测试用错误的用户名与密码连接:

可以看到,虽然连接的时候报用户名与口令错误,但终究是没有继续被服务器block了。

然后,用正确的用户名与口令登陆,看看host_cache中的计数是否会清零:

可以看到,SUM_CONNECT_ERRORS的值确实被清零了。

因此,验证了官方文档上关于该参数的描述。

二、

为了继续说第二种解决方案,先按照上述的telnet的方法,复现错误:

提升 host_cache_size:

可以看到,每次重设 host_cache_size 其实都会清空 host_cache表。

再次尝试连接:

可以看到,确实解除了 服务器 对客户端主机的 block。

三、

为了演示第三种方式,依旧首先复现问题:

执行:flush hosts

可以看到,flush hosts 其实是清空 host_cache表。

再次连接试试:

可以看到,连接没有问题。


至此,已经可以明白参数 max_connect_errors 参数的工作方式。

这里,还需要说明的是:

在以上所有的步骤中,参数skip_name_resolve的状态都是OFF的:

如果该参数打开,那么不论发生多少次连接请求未成功的中断,host_cache表都不会被更新,永远都处于Empty set的状态。

此外,顺便说一下,在上面验证过程中,MySQL的错误日志如下所示:

其中:
[Note] Got timeout reading communication packets

就是在执行telnet模拟错误的时候的日志报错;
可以看到,从这个错误日志的报错信息上是无法判断到底错误来自哪个主机的,只能看到max_connect_errors相关的错误被触发了。

而想要看具体哪些主机正在触发该参数,需要监控performance_schema.host_cache表。


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

隐藏
变装