MySQL 案例:init_connect 引发的 Lost connection

2020-10-21 15:12:35 浏览数 (1)

前言

最近发现一个比较奇特的 Lost connection 问题,详细测试和验证了一下,记录下来。

问题描述

用户反馈连接到数据库之后,执行show database的时候会断开连接。

原因分析

从反馈上来看,用户是可以登录到数据库的,说明网络的连通性,用户名密码方面没有问题,权限方面如果有问题的话,一般也不会有 Lost connection 的报错,MTU 的问题一般也是返回不了结果。光从问题描述上看,感觉这个问题就没什么头绪了。

叫上同事一起看这个问题之后,发现一个不寻常的地方:这个参数实例的 init_connect 参数设置了内容,看起来比较奇怪:innodb_adaptive_hash_index=ON

按个人的经验来看,这个参数一般是会写完整的 SQL 语句,比如set global xxx=xxx,这种直接写参数的可能会有点问题。查了一下官方文档,有如下描述:

A string to be executed by the server for each client that connects. The string consists of one or more SQL statements, separated by semicolon characters. For users that have the SUPER privilege, the content of init_connect is not executed. This is done so that an erroneous value for init_connect does not prevent all clients from connecting. For example, the value might contain a statement that has a syntax error thus causing client connections to fail. Not executing init_connect for users that have the SUPER privilege enables them to open a connection and fix the init_connect value.

可以看到对这个参数的内容描述是 “SQL 语句”,说明这个参数的内容可能被拿来直接执行了。

为了方便检查日志,用自建的 MySQL 5.7.31 测试一下:

代码语言:txt复制
mysql> set global init_connect = "sort_buffer_size = 41943040";
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%init_conn%';
 --------------- ----------------------------- 
| Variable_name | Value                       |
 --------------- ----------------------------- 
| init_connect  | sort_buffer_size = 41943040 |
 --------------- ----------------------------- 
1 row in set (0.00 sec)

mysql> exit
Bye
root@test-debian:~# mysql -h127.0.0.1 -utest -ptest
...省略...
Server version: 5.7.31-log MySQL Community Server (GPL)
...省略...
mysql> show databases;
ERROR 2013 (HY000): Lost connection to MySQL server during query
mysql>

发现可以复现 Lost connection 现象,说明问题就在这里了,如果是直接执行了语句,那么报错信息可能会记录在 error log:

代码语言:txt复制
2020-10-21T06:32:38.520817Z 53620 [Warning] Aborted connection 53620 to db: 'unconnected' 
user: 'test' host: '127.0.0.1' (init_connect command failed)
2020-10-21T06:32:38.520844Z 53620 [Warning] You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the right syntax 
to use near 'sort_buffer_size = 41943040' at line 1

试一试,如果改成正常的 SQL 语句,看看效果怎么样:

代码语言:txt复制
mysql> set global init_connect = "set session sort_buffer_size = 41943040";
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye
root@VM-56-136-debian:~# mysql -h127.0.0.1 -utest -ptest
...省略...
Server version: 5.7.31-log MySQL Community Server (GPL)
...省略...
mysql> show databases;
 -------------------- 
| Database           |
 -------------------- 
| information_schema |
 -------------------- 
1 row in set (0.00 sec)

mysql> show variables like '%init_conn%';
 --------------- ----------------------------------------- 
| Variable_name | Value                                   |
 --------------- ----------------------------------------- 
| init_connect  | set session sort_buffer_size = 41943040 |
 --------------- ----------------------------------------- 
1 row in set (0.00 sec)

mysql>

PS:腾讯云数据库 MySQL 也会遇到一样的问题,使用的时候需要注意

扩展一下

这个功能也会有一部分 DBA 拿来做一些特殊用途,比如对业务账号做一些限制之类的,参考文档的描述,所有非 super 权限的账号在登录的时候都会执行一次。而 DBA 账号通常会有 super 权限,登录的时候是不会执行 init_connect 记录的命令

解决方案

在 init_connect 参数中设置正确的 SQL 语句。

0 人点赞