【GaussDB】使用MySQL客户端连接到GaussDB的M-Compatibility数据库

【GaussDB】使用MySQL客户端连接到GaussDB的M-Compatibility数据库

概述

GaussDB 从内核 505.1 版本(2024年4月发布)起,新增了一种新的兼容模式 M-Compatibility ,这是一种整体上比之前的B模式对MySQL兼容性更高的模式。这种M模式在建库时会自动使用模板库 templatem

之所以需要再新增一种M模式,我猜测是因为GaussDB发现有些MySQL兼容性已经完全违背了内核的SQL及存储逻辑,无法通过参数调整进行兼容,为了不影响原有B模式的用户,必须新增一种兼容模式来隔离之前的逻辑。

新的这个M兼容模式,可以用MySQL客户端进行连接,但是实际使用过程中,可能会有一些坑在文档中并未详细说明,本文就来介绍一下"使用MySQL客户端连接到GaussDB的M-Compatibility数据库"的正确姿势。

测试环境 :本文使用的GaussDB内核版本为 506.0 SPC0100


建库操作

指定M兼容模式建库:

sql 复制代码
CREATE DATABASE mysql DBCOMPATIBILITY='M';

修改参数

参考文档

添加客户端IP到数据库白名单

将客户端IP添加到数据库白名单,具体操作请联系管理员处理。

设置兼容性参数

请参见《管理员指南》中的"配置运行参数"章节,配置相关GUC参数并重启数据库。

参数配置:

  1. 配置协议监听的TCP端口号,设置GUC参数 plat_compat_server_port 为合理端口
  2. 如果 使用到RSA,需要设置GUC参数 plat_compat_allow_public_key_retrievalon
  3. 将GUC参数 m_format_dev_version 设置为 "s2"

执行命令:

bash 复制代码
gs_guc reload -I all -N all -c "plat_compat_server_port=3306"
gs_guc reload -I all -N all -c "plat_compat_allow_public_key_retrieval=on"
gs_guc reload -I all -N all -c "m_format_dev_version='s2'"

创建连接用户(可选)

sql 复制代码
CREATE USER mysql_user PASSWORD 'Gaussdb@123' SYSADMIN MONADMIN;

连接测试

初始连接问题

使用MySQL客户端连接时出现报错:

错误信息: plat_compat_b_conn_handshake, handshake error.

Java代码连接测试

尝试手写一段Java代码进行连接:

java 复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class MySQLCreateTable {
    public static void main(String[] args) {
        String url = "jdbc:mysql://192.168.163.119:3306/mysql";
        String user = "mysql_user";
        String password = "Gaussdb@123";

        try (Connection conn = DriverManager.getConnection(url, user, password);
             Statement stmt = conn.createStatement()) {

            String sql = "CREATE TABLE IF NOT EXISTS users2 (" +
                         "id INT PRIMARY KEY AUTO_INCREMENT," +
                         "name VARCHAR(100) NOT NULL," +
                         "email VARCHAR(100) NOT NULL UNIQUE" +
                         ")";
            stmt.executeUpdate(sql);
            System.out.println("Table created successfully.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果: 也报错了

java 复制代码
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)
        at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
        at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:827)
        at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:447)
        at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:237)
        at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199)
        at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:681)
        at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:229)
        at MySQLCreateTable.main(MySQLCreateTable.java:11)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
        at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167)
        at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:340)
        at com.mysql.cj.protocol.a.NativeAuthenticationProvider.negotiateSSLConnection(NativeAuthenticationProvider.java:777)
        at com.mysql.cj.protocol.a.NativeAuthenticationProvider.proceedHandshakeWithPluggableAuthentication(NativeAuthenticationProvider.java:486)
        at com.mysql.cj.protocol.a.NativeAuthenticationProvider.connect(NativeAuthenticationProvider.java:202)
        at com.mysql.cj.protocol.a.NativeProtocol.connect(NativeProtocol.java:1348)
        at com.mysql.cj.NativeSession.connect(NativeSession.java:163)
        at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:947)
        at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:817)
        ... 6 more
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
        at java.base/sun.security.ssl.HandshakeContext.<init>(HandshakeContext.java:172)
        at java.base/sun.security.ssl.ClientHandshakeContext.<init>(ClientHandshakeContext.java:103)
        at java.base/sun.security.ssl.TransportContext.kickstart(TransportContext.java:240)
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:448)
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:426)
        at com.mysql.cj.protocol.ExportControlled.performTlsHandshake(ExportControlled.java:316)
        at com.mysql.cj.protocol.StandardSocketFactory.performTlsHandshake(StandardSocketFactory.java:188)
        at com.mysql.cj.protocol.a.NativeSocketConnection.performTlsHandshake(NativeSocketConnection.java:99)
        at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:331)
        ... 13 more

解决方案

查看官方文档《基于MySQL JDBC开发-开发步骤-连接数据库-以常规方式连接》,发现文档中的连接串是:

java 复制代码
String sourceURL = "jdbc:mysql://$ip:$port/database?useSSL=false&allowPublicKeyRetrieval=true";

多了两个参数,逐步测试:

步骤1:添加 useSSL=false

先加一个 useSSL=false 参数测试。

结果: 出现了和mogeaver一样的报错。

步骤2:添加 allowPublicKeyRetrieval=true

再把另一个参数也加上去 allowPublicKeyRetrieval=true

结果: ✅ 执行成功了!

验证其他客户端

在mogeaver里也加上这个参数 allowPublicKeyRetrieval=true

结果: ✅ 也连接成功了!

说明: 但是mogeaver里的useSSL为true,之所以没有报错,是因为mogeaver里还自动加上了enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2

连接参数总结

根据测试,自己写的Java代码,连接时必须加上:

  • 方案一: useSSL=false&allowPublicKeyRetrieval=true
  • 方案二: useSSL=true&enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2

常见问题及解决

如果是普通的测试人员,测到这里,就会认为连接测试这一项已经测试通过了,但是换几个不同的环境里的GaussDB去测,还可能会出现这样的报错:

问题:Access denied for user

错误信息: Access denied for user

注意: 如果是用户名密码错误,也会报这个错,所以先要用gsql测试一下用户名密码是否正确,确认用户名密码没有写错后,那么问题就可能发生在密码加密方式上。

原因分析

在官方文档[《配置客户端接入认证》](https://support.huawei.com/carrier/docview?nid=DOC1101458028\&path=PBI1-253383977/PBI1-23710112/PBI1-23710137/PBI1-256197501\&partNo=k00e)这个章节里写着:

外部客户端使用M-Compatibility兼容协议远程连接M-Compatibility数据库时,只支持 sha256认证方式

于是去检查gs_hba.conf,发现无论是配置成md5还是sha256,Access denied for user这个问题都依然存在。

然后继续翻官方文档,发现在《设置密码安全策略》这个章节里写着:

使用M-Compatibility兼容协议连接数据库时,仅支持sha256加密模式,即 password_encryption_type = 2

也就是说,必须确保数据库用户的密码存储时,必须是仅存储sha256密文,不能支持其他方式。

解决步骤
  1. 修改密码加密参数:
bash 复制代码
gs_guc reload -I all -N all -c "password_encryption_type=2"
  1. 重新设置用户密码:
sql 复制代码
ALTER USER mysql_user PASSWORD 'mysql_123';

到此,使用MySQL客户端连接GaussDB就顺利了...吗?


进阶配置:RSA加密支持

搜索官方文档,发现还有这么一个章节:《使用RSA加密登录密码》

RSA加密登录配置要求:

  1. 设置 plat_compat_allow_public_key_retrieval 参数值为 on
  2. 设置 require_ssl 参数值为 off
  3. 设置 hba type 参数值为 hosthostnossl

也就是说,如果 require_sslon,那么本文的配置方式也会连接不上去了。

连接方式总结

综合分散在文档各个地方的信息来看,连接应该是可以用RSA或者不用RSA:

服务端配置 客户端配置 说明
plat_compat_allow_public_key_retrieval=off useSSL=true&enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2 禁用RSA,使用SSL
plat_compat_allow_public_key_retrieval=on useSSL=false&allowPublicKeyRetrieval=true 使用RSA,不使用SSL
plat_compat_allow_public_key_retrieval=on useSSL=true&enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2 允许使用RSA,但仍然使用SSL

实测也的确如此。


补充说明

另外,数据库里还有个参数 plat_compat_default_database,可以配置MySQL协议连过来需要连接哪个库。

  • 在没有设置这个参数时: JDBC连接串里的dbname就真的是GaussDB里面的数据库名称
  • 如果设置了这个参数: JDBC连接串里的dbname就是 plat_compat_default_database 指定的库下的schema名称

重要声明

⚠️ 版本说明 :本文这里的这些内容,仅为在 506.0 SPC0100 集中式版本上测试的结果,不代表新版本的表现(目前已知有些东西在新版本改了)。


相关文档

相关推荐
yuzhiboyouye1 小时前
内连接,左连接,右连接怎么区别开来?
数据库
铭毅天下1 小时前
Easysearch 版本进化全图——从 ES 国产替代到 AI Native 搜索数据库
大数据·数据库·人工智能·elasticsearch·搜索引擎
muddjsv1 小时前
SQL 最常用技能详解与实战示例
数据库·sql·mysql
muddjsv2 小时前
大中小型企业数据配置年度成本估算分析
数据库·企业运营
ᰔᩚ. 一怀明月ꦿ3 小时前
MySQL 学习目标
学习·mysql·adb
塔能物联运维3 小时前
存量机房升级成为行业主流方向:热管理重构算力中心价值路径
数据库
lqj_本人3 小时前
鸿蒙electron跨端框架PC工志簿实战:项目、工时、阻塞和下一步都要有位置
数据库·华为·harmonyos
刘一说3 小时前
AI科技热点日报 | 2026年5月22日
数据库·人工智能·科技
LCG元3 小时前
RAG工程指南:从基础检索到生产部署全解析
java·运维·数据库
godspeed_lucip4 小时前
LLM和Agent——专题3: Agentic Workflow 入门(1)
大数据·数据库·人工智能