首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >连接数据库失败,难道MySQL 5.7客户端与8.0数据库不兼容?

连接数据库失败,难道MySQL 5.7客户端与8.0数据库不兼容?

作者头像
吹水老王
修改2022-05-19 14:51:42
9.8K0
修改2022-05-19 14:51:42
举报
文章被收录于专栏:MySQL 8.0MySQL 8.0

连接数据库失败,难道MySQL 5.7客户端与8.0数据库不兼容?

前言

线上业务数据库升级到MySQL 8.0.28之后,业务侧使用MySQL 5.5版本的mysql_api连接数据库正常,但是我们管理端使用旧的MySQL 5.7客户端连接数据库却是失败的。难道MySQL 5.7的客户端与8.0的数据库之间不兼容? 这个问题可就比较严重了,可能成为数据库升级路上的拦路虎。一下就勾起了吹水老王极大的兴致,我们一起来分析一下。

1. MySQL 8.0数据库连接失败

我们线上将一套数据库从MySQL 5.7.26升级到MySQL 8.0.28之后,业务侧有两种程序语言,c++程序通过MYSQL_API连接数据库,java程序通过JDBC连接数据库,升级之后没有任何异常;但是,我们DB管理端的监控通过原有的MySQL 5.7客户端连接数据库失败。

JDBC与这个问题不相关,我们暂且抛去不谈;现在问题就是,MYSQL_API使用的MySQL 5.5客户端可以正常连接8.0.28数据库,MySQL 5.7客户端却不能。

为了明确具体问题,我们先做个测试,分别使用MySQL 5.5/5.6/5.7的客户端连接MySQL 8.0数据库。

# 使用MySQL 5.7的客户端连接MySQL 8.0.28时报错
# /usr/local/mysql/bin/mysql --version
/usr/local/mysql/bin/mysql  Ver 14.14 Distrib 5.7.26, for el7 (x86_64) using  EditLine wrapper

# /usr/local/mysql/bin/mysql -h9.135.1.1 -P3307 -utest -ptest
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2026 (HY000): SSL connection error: unknown error number
# 使用MySQL 5.5的客户端连接MySQL 8.0.28,连接成功。
# /bin/mysql --version
/bin/mysql.bak  Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (x86_64) using readline 5.1

# /bin/mysql -h9.135.1.1 -P3307 -utest -ptest
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.28 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> select version();

最终,得到以下结果:

  1. 使用MySQL 5.7的客户端或者mysql_api连接MySQL 8.0.28以上版本的数据库时失败;
  2. 而使用MySQL 5.5和5.6版本的客户端连接MySQL 8.0.28以上版本数据库却是正常的;
  3. 使用MySQL 5.5/5.6/5.7版本的客户端连接MySQL 8.0.28以下版本(如MySQL 8.0.23)都是正常的。

这就不得不让人怀疑,难道5.7版本的MySQL客户端与8.0版本数据库是否存在兼容性问题?

2. 连接失败与SSL相关

首先,报错信息为SSL connection error,可以猜想使用MySQL 5.7的客户端连接MySQL 8.0数据库时的报错与SSL相关。

我们来回忆一下数据库连接基础知识。 MySQL数据库的连接方式通常有两种,一种是通过TCP/IP连接,即通过数据库的端口进行通信,另外一种方式是通过本地SOCKET连接,即在客户端在数据库本机通过本地的socket文件连接数据库。SOCKET连接比TCP/IP连接方式要快,但是只适用于客户端和服务端在同一台unix主机的场景。

我们可以验证一下,MySQL 5.7的客户端使用socket方式连接MySQL 8.0数据库是否正常。

# 这里我们使用root@localhost用户连接数据库

# /usr/local/mysql/bin/mysql --version
/usr/local/mysql/bin/mysql  Ver 14.14 Distrib 5.7.26, for el7 (x86_64) using  EditLine wrapper

# /usr/local/mysql/bin/mysql -uroot -proot -S /data/MySQLData_3307/data/mysql.sock

Server version:8.0.28 MySQL Community Server - GPL
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.28    |
+-----------+
1 row in set (0.00 sec)

可以看到,使用MySQL 5.7的客户端通过本地socket的方式可以正常连接MySQL 8.0.28以上版本的数据库。那么也就证明了5.7版本的客户端与8.0版本的数据库本身其实不存在兼容性问题。MySQL 5.7客户端连接失败只是与TCP的SSL加密连接相关。

3. 为什么5.5/5.6连接MySQL 8.0是正常的,偏偏5.7客户端连接失败

3.1 MySQL 5.7客户端的变化

MySQL 5.7客户端连接8.0数据库失败与SSL加密连接相关。实际上在我们的生产环境,MySQL客户端或者mysql_api连接数据库通常是不使用SSL的。既然MySQL 5.7的客户端与MySQL 5.5/5.6客户端在SSL方面的行为有差异,我们就来看看两者的默认行为有什么不同。

使用mysql --help查看MySQL客户端帮助中与SSL相关的配置,可以看到:MySQL 5.5客户端默认关闭了SSL,而在MySQL 5.7的客户端中默认是开启SSL的,并且多了一个ssl-mode参数配置SSL连接模式。

# MySQL 5.5 客户端默认关闭SSL
# /bin/mysql.bak --help | grep ssl
  --ssl               Enable SSL for connection (automatically enabled with
ssl                               FALSE
# MySQL 5.7 客户端默认开启SSL
# /usr/local/mysql/bin/mysql --help | grep ssl
  --ssl-mode=name     SSL connection mode.
  --ssl               Deprecated. Use --ssl-mode instead.
                      (Defaults to on; use --skip-ssl to disable.)
ssl                               TRUE

既然SSL配置在MySQL 5.7和之前版本的客户端中存在差异,那么我们可以再验证一下,MySQL 5.7在显式关闭SSL的情况下是否能够连接MySQL 8.0成功。

# /usr/local/mysql/bin/mysql --skip-ssl -h9.135.1.1 -P3307 -utest -ptest
Server version: 8.0.28 MySQL Community Server - GPL
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.28    |
+-----------+
1 row in set (0.00 sec)

果然,在显式设置–skip-ssl禁用SSL的情况下,MySQL 5.7的客户端连接MySQL 8.0也是成功的。

至于MySQL 5.7的客户端SSL配置的变更,我们可以通过官方文档 配置MySQL使用加密连接 来确认一下。 By default, MySQL client programs attempt to establish an encrypted connection if the server supports encrypted connections, with further control available through the --ssl-mode option:

  • In the absence of an --ssl-mode option, clients attempt to connect using encryption, falling back to an unencrypted connection if an encrypted connection cannot be established. This is also the behavior with an explicit --ssl-mode=PREFERRED option.

根据MySQL 5.7的文档描述,可以看出,MySQL 5.7的客户端如果没有显式配置–ssl-mode参数,并且数据库端支持SSL加密连接的话,那么客户端会尝试创建SSL加密连接;如果SSL加密连接失败则退而求其次使用不加密连接。

我们注意到,MySQL 5.7的客户端创建SSL加密连接有两个必要条件:1)客户端没有显式禁用SSL;2)数据库端支持SSL加密连接。

3.2 MySQL 8.0数据库端的变化

第一点已经很明确了,MySQL 5.7的客户端默认是开启SSL的。我们来看看第二点,数据库端支持SSL加密连接。

通过对比,我们发现MySQL 8.0 与 MySQL 5.7数据库端的默认配置也存在差异。MySQL 5.7的数据库中默认是禁用SSL的,而在MySQL 8.0中默认是开启SSL的。

# MySQL 5.7数据库中默认是禁用SSL的
mysql> show global variables like '%ssl%';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| have_openssl  | DISABLED |
| have_ssl      | DISABLED |
# MySQL 8.0数据库中默认是启用SSL的
mysql> show global variables like '%ssl%';
+-------------------------------------+-----------------+
| Variable_name                       | Value           |
+-------------------------------------+-----------------+
| have_openssl                        | YES             |
| have_ssl                            | YES             |

小结:MySQL 8.0数据库初始化时默认开启了SSL,之前版本的数据库默认是禁用SSL的。同时,MySQL 5.7之前版本的客户端默认禁用SSL,而MySQL 5.7版本的客户端在数据库端支持SSL的情况下会尝试创建SSL加密连接。所以,MySQL 5.5/5.6版本客户端不使用加密连接MySQL 8.0数据库,连接是成功的;而MySQL 5.7版本客户端使用SSL加密连接MySQL 8.0数据库,连接失败。


4. 为什么5.7客户端连接8.0.28失败,连接8.0.28之前版本数据库正常呢

这是由于在MySQL 8.0.28版本开始,数据库层默认的tls版本为TLSv1.2,并且不再支持旧版本的TLSv1和TLSv1.1连接;而在之前版本中的默认tls版本为TLSv1。

参考文档:Changes in MySQL 8.0.28

From MySQL 8.0.28, client programs, including MySQL Shell, that support a --tls-version option for specifying TLS protocols for connections to the MySQL server cannot make a TLS/SSL connection with the protocol set to TLSv1 or TLSv1.1. If a client attempts to connect using these protocols, for TCP connections, the connection fails, and an error is returned to the client.

验证一下,对比MySQL 8.0.28数据库和MySQL 5.7客户端支持的TLS_VERSION。

# MySQL 8.0.28数据库中默认tls_version
mysql> show global variables like '%tls%';
+------------------------+-----------------+
| Variable_name          | Value           |
+------------------------+-----------------+
| admin_tls_version      | TLSv1.2,TLSv1.3 |
| tls_version            | TLSv1.2,TLSv1.3 |
+------------------------+-----------------+
# MySQL 5.7客户端支持的tls_version
# /usr/local/mysql/bin/mysql --help | grep tls
--tls-version=name  TLS version to use, permitted values are: TLSv1, TLSv1.1

5. 解决方案

经过老王一番大胆设想小心求证,问题原因已经显而易见。综上,数据库端MySQL 8.0初始化时默认启用了SSL,并且从MySQL 8.0.28版本开始将默认TLS版本升级为TLSV1.2,并且不再支持旧版本的TLS;而MySQL 5.7版本的客户端包括mysql_api默认会尝试与数据库端以TLSV1或TLSV1.1版本的SSL建立加密连接,TLS版本在数据库层和客户端之间的不兼容导致MySQL 5.7的客户端无法连接MySQL 8.0.28以上数据库。

MySQL 5.7的客户端与8.0数据库本身并不存在兼容性问题,只是SSL版本不兼容而已。解决方案也就很简单了,要么在数据库层禁用SSL,要么在低版本客户端中禁用SSL即可。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 连接数据库失败,难道MySQL 5.7客户端与8.0数据库不兼容?
  • 前言
  • 1. MySQL 8.0数据库连接失败
  • 2. 连接失败与SSL相关
  • 3. 为什么5.5/5.6连接MySQL 8.0是正常的,偏偏5.7客户端连接失败
    • 3.1 MySQL 5.7客户端的变化
      • 3.2 MySQL 8.0数据库端的变化
      • 4. 为什么5.7客户端连接8.0.28失败,连接8.0.28之前版本数据库正常呢
      • 5. 解决方案
      相关产品与服务
      云数据库 SQL Server
      腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档