一、报错信息客户端程序错误:Host 10.*.*. is blocked because of many connection errors; unblock with ‘mysqladmin flush-hosts’
mysql错误日志显示:[Warning] IP address 'xxxx' could not be resolved: Name or service not known
二、错误原因分析:
首先介绍三个参数:
1)max_connect_errors参数:
在max_connect_errors之后,来自主机的连续连接请求在没有成功连接的情况下被中断(超过了connect_timeout时间也没有登录上mysql),服务器将阻止该主机进行进一步的连接。如果在前一个连接中断后,在少于max_connect_errors尝试的时间内成功建立了与主机的连接,则主机的错误计数将清除为零。要解除阻止被阻止的主机,请刷新主机缓存;请参阅刷新主机缓存。
2)connect_timeout参数:
mysqld服务器在使用Bad握手进行响应之前等待连接数据包的秒数。默认值为10秒。如果客户端经常遇到以下错误,增加connect_timeout值可能会有所帮助:Lost connection to MySQL server at 'XXX', system error: errno.
3)skip-name-resolve参数
检查客户端连接时是否解析主机名。如果此变量为OFF,则mysqld在检查客户端连接时解析主机名。如果是ON,则mysqld只使用IP号码;在这种情况下,授予表中的所有主机列值都必须是IP地址;
原因分析:
当客户端连接服务端超时(超过connect_timeout), 服务端就会给这个客户端记录一次error,当出错的次数达到max_connect_errors的时候,这个客户端就会被锁定。所以根据业务来尽量把这个值设置大一点,mysql默认值为100,我们可以根据具体需要设置大一点,并非越大越好,越大被攻击时安全性越低。
使用命令:
set global max_connect_errors=300;
mysql日志显示[Warning] IP address 'xxxx' could not be resolved: Name or service not known,那是因为mysql默认会反向解析DNS,对于访问者Mysql不会判断是hosts还是ip都会进行dns反向解析,频繁地查询数据库和权限检查,这大大增加了数据库的压力,导致数据库连接缓慢,严重的时候甚至死机,出现“连接数据库时出错”等字样。
因为MySQL实例设置skip-name-resolve=no,也就是说每次有客户端连接,MySQL都会去尝试进行dns反向解析,由于mysql服务器/etc/hosts没有配置客户端的ip解析,并且mysql服务器配置了dns,但是dns中也也没有配置客户端ip的解析,就会在dns中查找解析的时间越来越长,导致登录验证的时间超过connect_timeout,进而导致max_connect_errors的累计值增加1;最后超过max_connect_errors的阈值,最终导致客户端被锁定!
mysql是这样来处理客户端解析过程的:
1,当mysql的client连过来的时候,服务器会主动去查client的域名。
2,首先查找 /etc/hosts 文件,搜索域名和IP的对应关系。
3,如果hosts文件没有,则查找DNS设置,如果没有设置DNS服务器,会立刻返回失败,就相当于mysql设置了skip-name-resolve参数,如果设置了DNS服务器,就进行反向解析,直到timeout。
mysql接收到连接请求后,获得的是客户端的ip,为了更好的匹配mysql.user里的权限记录(某些是用hostname定义的)。
如果mysql服务器设置了dns服务器,并且客户端ip在dns上并没有相应的hostname,那么这个过程很慢,导致连接等待。
根本原因:
mysql 没有设置skip-name-resolve=1,此时对于访问者Mysql不会判断是hosts还是ip都会进行dns反向解析,如果/etc/hosts 文件没有匹配到客户端IP,进而去找dbs,因为dns里面也没有配置客户端ip的解析,频繁地查询数据库和权限检查,这大大增加了数据库的压力,导致数据库连接缓慢,所以就可能会超过connect_timeout,进而导致触发max_connect_errors阈值,导致客户端被锁定;
三、解决办法
1、禁用dns反查----根本解决办法进入/etc 找到mysql的配置文件my.cnf(linux环境下)或者my.ini(windows环境下)进行编辑加入如下一行即可:需要重启下MySQL实例[mysqld]skip-name-resolve如果不能重启MySQL数据库,可以把client的ip写在mysql服务器的/etc/hosts文件里,随便给个名字就可以了!找到了就不会去遍历dns;
2、清楚缓存----- 当问题已经发生了,只能这样处理了!也可以使用清楚缓存的方法。这样就会把计数清理掉。到安装bin目录下,使用mysqladmin -u root -p flush-hosts命令,输入密码后,即完成清楚缓存。也可以进入mysql控制台,执行: flush hosts即mysql -u -p -h 登录控制台,然后执行 flush hosts;
最终解决办法
1、可以尝试在/etc/hosts文件添加客户端ip解析--- 不重启的情况下解决;
2、可以设置skip-name-resolve跳过dns解析 ----需要重启MySQL;
3、如果也可以尝试把mysql服务器的dns配置去掉。这样也能快速返回错误,就不能使用主机名来做白名单控制了
4、还可以尝试调大connect_timeout,但是这个无法绝对解决问题,例如说你dns没有配置客户端解析,那最终还是得timeout,进而增加一个max_connect_errors值