Mysql配置ssl证书

Mysql配置ssl证书

𝓓𝓸𝓷 Lv6

Mysql8主从配置ssl证书,openssl配置ssl证书

一、证书介绍

MySQL8 生成 SSL 证书主要有‌3 种方式‌,具体如下:

  • 自动生成(推荐新手)‌:MySQL 8 在启动时会自动检测数据目录(datadir)下是否缺少 ca.pem、server-cert.pem、server-key.pem 等 SSL 文件。如果缺失且未指定 SSL 相关启动参数,服务器会自动生成一套自签名证书和密钥文件,包括 ca.pem、server-cert.pem、server-key.pem、client-cert.pem、client-key.pem 等。这种方式最省事,但生成的证书是自签名的,安全性相对较低,证书中没有对应的 SAN(Subject Alternative Name)。

  • 使用 mysql_ssl_rsa_setup 命令生成‌:MySQL 8 自带的工具,执行 mysql_ssl_rsa_setup --datadir=/var/lib/mysql --uid=mysql 即可在数据目录下生成所需的证书和密钥文件,文件列表与自动生成方式一致。‌‌这是最简单、最标准的生成自签名证书的方法。它会自动生成 CA 证书、服务器证书和密钥,以及 RSA 密钥对(用于安全密码交换),这种方式生成的SSL证书不带主机名,适用于内部加密传输、不严格校验主机名的客户端连接。现代许多客户端库(如 Java 的 JDBC Driver、Python 的 mysql-connector-python 或 Go 的驱动)在进行 SSL 握手时,会严格校验服务器证书中的主机名。如果客户端通过 IP 地址(如 192.168.1.100)或特定域名连接,而证书中既没有对应的 SAN,CN 也不是该 IP/域名(CN 是固定的长字符串),客户端可能会抛出类似 ERROR 2026 (HY000): SSL connection error: error:0A000086:SSL routines::certificate verify failed 或 Certificate doesn't match 的错误。**mysql_ssl_rsa_setup 从 MySQL 8.0.34 开始被标记为弃用(deprecated)‌,在 8.0.34 及后续 8.0.x 版本中仍可使用,但会提示弃用警告,官方建议不再依赖它。推荐使用 OpenSSL。**‌

  • 使用 OpenSSL 命令手动生成(适用于生产环境/自定义CA/等保)‌:完全通过 openssl 命令生成 CA 证书、服务器证书和客户端证书,可以自定义证书的有效期、密钥长度和扩展属性。这种方式灵活性最高,适合需要定制证书信息或满足特定安全要求的场景。‌‌

兼容性建议:

  • ‌开发/测试环境‌:通常可以将客户端的 SSL 验证模式设置为 VERIFY_CA 或 PREFERRED,而不是严格的 VERIFY_IDENTITY,这样可以绕过主机名匹配检查,仅验证证书是否由可信 CA 签发。
  • ‌生产环境‌:如果需要严格的主机名验证(VERIFY_IDENTITY),‌不建议‌使用 mysql_ssl_rsa_setup 生成的证书。应使用 OpenSSL 手动生成包含正确 SAN(如 DNS:mydb.example.com, IP:192.168.1.100)的证书,或者使用 Let’s Encrypt 等公共 CA 签发的证书。

证书要求:

  • server-key.pem 权限必须为 600,属主 mysql
  • 证书路径用绝对路径,且 mysqld 进程用户可读,如果证书放置在mysql数据目录下,则可以不使用绝对路径
  • 证书 CN 或 SAN 要包含主库实际访问地址(IP 或域名),否则握手会报证书校验失败
  • 从库作为客户端连接时,也需要 ca.pem(CA 证书),把主库的client-cert.pem、client-key.pem 一并拷贝过去

证书权限:

1
2
3
4
5
6
7
8
9
10
11
12
🔸确保所有 pem 文件属主为 mysql:
chown mysql:mysql /var/lib/mysql/*.pem

🔸私钥文件必须设置为 600 (仅所有者读写):
chmod 600 /var/lib/mysql/server-key.pem
chmod 600 /var/lib/mysql/ca-key.pem
chmod 600 /var/lib/mysql/client-key.pem

🔸公钥/证书文件可设为 644:
chmod 644 /var/lib/mysql/ca.pem
chmod 644 /var/lib/mysql/server-cert.pem
chmod 644 /var/lib/mysql/client-cert.pem

SSL证书服务器名称解析机制:

SSL/TLS协议中的服务器名称验证是确保安全连接的关键环节。根据RFC 6125(通用服务器身份验证规范)和其前身RFC 2818(HTTPS特定规范),主机名验证遵循明确的优先级规则。当证书包含Subject Alternative Names(SAN)扩展时,系统必须优先使用SAN中的dNSName(域名)或iPAddress(IP地址)进行匹配。只有在SAN扩展不存在的情况下,才会回退到使用Common Name(CN)字段。

浏览器与Java实现的差异:

浏览器在处理证书验证时通常表现出更大的灵活性。许多浏览器实现会同时检查CN字段和SAN扩展,甚至在CN字段包含有效主机名时可能忽略SAN的缺失。这种宽松的实现方式源于历史兼容性考虑和RFC 2818中”most specific Common Name”定义的模糊性。

相比之下,Java的安全实现更加严格地遵循规范。从Java 7开始,sun.security.util.HostnameChecker类明确要求:当连接使用主机名时,证书必须包含匹配的dNSName SAN;当连接使用IP地址时,证书必须包含匹配的iPAddress SAN。如果缺少相应的SAN扩展,即使CN字段包含正确的主机名或IP地址,验证也会失败并抛出java.security.cert.CertificateException: No subject alternative names present异常。

SSL证书的主机名位置:

SSL证书的主机名‌不在server.key里,也不在CA证书里‌,而是在‌服务器证书(server.crt)‌的‌Subject字段(CN)‌或‌SAN扩展字段‌里。‌‌

简单说:

  • ‌server.key(私钥)‌:只存密钥,不含主机名信息。
  • ‌ca.crt(CA根证书)‌:是签发机构自己的证书,里面是CA的主机名,跟你的服务器主机名无关。
  • ‌server.crt(服务器证书)‌:这才是关键。客户端校验主机名时,看的是这张证书里的 ‌CN‌(Common Name)和 ‌SAN‌(Subject Alternative Name)字段。‌‌

需要注意:现代浏览器和HTTP客户端‌主要校验SAN,CN只作为备用‌;如果证书里有SAN但没覆盖你访问的主机名,即使CN匹配也会报错。‌‌

生成证书时,确保:

🔸‌CN‌ 填服务器主机名或IP,比如 server.example.com。

🔸SAN‌ 通过 subjectAltName 显式声明域名和IP,比如 DNS:server.example.com, IP:192.168.1.100

二、mysql_ssl_rsa_setup生成ssl证书

1.创建ssl证书目录(主库和从库)
1
2
mkdir /etc/mysql/ssl
chown mysql.mysql /etc/mysql/ssl
2.生成ssl证书(主库和从库)
1
2
3
4
5
6
7
8
9
10
11
12
mysql_ssl_rsa_setup --datadir=/etc/mysql/ssl --uid=mysql

# ls -l
total 32
-rw-------. 1 mysql mysql 1675 Oct 15 10:33 ca-key.pem
-rw-r--r--. 1 mysql mysql 1107 Oct 15 10:33 ca.pem
-rw-r--r--. 1 mysql mysql 1107 Oct 15 10:33 client-cert.pem
-rw-------. 1 mysql mysql 1679 Oct 15 10:33 client-key.pem
-rw-------. 1 mysql mysql 1675 Oct 15 10:33 private_key.pem
-rw-r--r--. 1 mysql mysql 451 Oct 15 10:33 public_key.pem
-rw-r--r--. 1 mysql mysql 1107 Oct 15 10:33 server-cert.pem
-rw-------. 1 mysql mysql 1675 Oct 15 10:33 server-key.pem
3.配置my.cnf(主库和从库)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
如果使用mysql自带的证书可以使用相对路径:
# vi /etc/ my.cnf
[mysqld]
#SSL:
ssl_ca = /etc/mysql/ssl/ca.pem
ssl_cert = /etc/mysql/ssl/server-cert.pem
ssl_key =/etc/mysql/ssl/server-key.pem
require_secure_transport = ON

# 【等保关键】强制所有连接使用 SSL,禁止明文连接
require_secure_transport = ON

# 限制 TLS 版本,禁用不安全的旧协议 (等保要求)
tls_version = TLSv1.2,TLSv1.3

# 限制加密套件,禁用弱加密算法
ssl_cipher = HIGH:!aNULL:!MD5:!RC4
4.重启数据库(主库和从库)
1
systemctl restart mysql
5.检查并验证ssl连接(主库和从库)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
SHOW VARIABLES LIKE 'have_ssl';      -- 必须为 YES
SHOW VARIABLES LIKE 'require_secure_transport'; -- 必须为 ON


mysql> show variables like 'have_ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_ssl | YES |
+---------------+-------+
1 row in set (0.04 sec)

mysql> show variables like 'require_secure_transport';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| require_secure_transport | ON |
+--------------------------+-------+
1 row in set (0.00 sec)

mysql> select @@GLOBAL.tls_version;
+----------------------+
| @@GLOBAL.tls_version |
+----------------------+
| TLSv1.2,TLSv1.3 |
+----------------------+
1 row in set (0.00 sec)

创建测试帐号并强制ssl:
create user test@'%' identified by '123456' require ssl;
grant all privileges on mydb.* to test@'%' ;

登录测试ssl:
mysql -utest -p --ssl-mode=require
mysql -utest -p --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-mode=VERIFY_CA
mysql -utest -p --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-mode=VERIFY_IDENTITY (失败,因为mysql_ssl_rsa_setup生成的证书没有主机名)
ERROR 2026 (HY000): SSL connection error: error:0A000086:SSL routines::certificate verify failed


mysql -utest -p --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-mode=VERIFY_CA
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 29
Server version: 8.0.34 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

You are enforcing ssl connection via unix socket. Please consider
switching ssl off as it does not make connection via unix socket
any more secure.
mysql> \s
--------------
mysql Ver 8.0.34 for Linux on x86_64 (MySQL Community Server - GPL)

Connection id: 29
Current database:
Current user: test@localhost
SSL: Cipher in use is TLS_AES_256_GCM_SHA384
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 8.0.34 MySQL Community Server - GPL
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
UNIX socket: /tmp/mysql.sock
Binary data as: Hexadecimal
Uptime: 20 min 1 sec

Threads: 2 Questions: 41 Slow queries: 0 Opens: 176 Flush tables: 3 Open tables: 95 Queries per second avg: 0.034
--------------

删除测试帐号:
mysql> delete from mysql.user where host='%' and user='test';
6.复制帐号强制SSL(主库)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mysql> select user,host from mysql.user;
+------------------+---------------+
| user | host |
+------------------+---------------+
| repl | 192.168.1.121 |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+---------------+
5 rows in set (0.00 sec)

-- MySQL 8.0.22+
mysql> alter user 'repl'@'192.168.1.121' require ssl;
Query OK, 0 rows affected (0.02 sec)

如果需要修改密码,使用以下命令指定认证插件为 mysql_native_password(兼容性好),并强制 SSL:
alter user 'repl'@'192.168.1.121' identified with mysql_native_password by '123456' require ssl;

-- 刷新权限
FLUSH PRIVILEGES;
7.将主库ssl证书传输至从库(从库)
1
2
3
4
5
6
7
8
9
10
11
# mkdir /etc/mysql/ssl_client
# chown mysql.mysql /etc/mysql/ssl_client
# scp -p 192.168.1.111:/etc/mysql/ssl/ca.pem /etc/mysql/ssl/client-cert.pem /etc/mysql/ssl/client-key.pem /etc/mysql/ssl_client
# chown mysql.mysql /etc/mysql/ssl_client/*.pem
# chmod 600 /etc/mysql/ssl_client/*key.pem

# ll /etc/mysql/ssl_client/
total 12
-rw-r--r--. 1 mysql mysql 1107 Oct 14 17:40 ca.pem
-rw-r--r--. 1 mysql mysql 1112 Feb 5 2025 client-cert.pem
-rw-------. 1 mysql mysql 1701 Feb 5 2025 client-key.pem
8.从库连接主库测试ssl连接(从库)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# mysql -urepl -p -h192.168.1.111 --ssl-ca=/etc/mysql/ssl_client/ca.pem --ssl-mode=VERIFY_CA
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 46
Server version: 8.0.34 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \s
--------------
mysql Ver 8.0.34 for Linux on x86_64 (MySQL Community Server - GPL)

Connection id: 46
Current database:
Current user: repl@192.168.1.121
SSL: Cipher in use is TLS_AES_256_GCM_SHA384
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 8.0.34 MySQL Community Server - GPL
Protocol version: 10
Connection: 192.168.1.111 via TCP/IP
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
TCP port: 3306
Binary data as: Hexadecimal
Uptime: 1 hour 19 min 35 sec

Threads: 2 Questions: 60 Slow queries: 0 Opens: 187 Flush tables: 3 Open tables: 106 Queries per second avg: 0.012
--------------
9.停止复制(从库)
1
2
mysql> stop replica;
Query OK, 0 rows affected, 1 warning (0.00 sec)
10.change replication source to(从库)

使用 CHANGE REPLICATION SOURCE TO (MySQL 8.0.22+) 或 CHANGE MASTER TO (旧版) 显式指定 SSL 参数,change replication source to必须带上SSL参数,‌重要‌:必须提供 SOURCE_SSL_CA 以验证主库身份,防止中间人攻击。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
如果主库的自签名证书缺失Subject Alternative Name (SAN)字段,MySQL 8.0.23+(尤其是 8.0.28+)在严格模式下会拒绝连接或导致 SSL 握手失败。

在这种情况下,为了让从库能够通过 SSL 成功连接主库,需要在 CHANGE REPLICATION SOURCE TO(或旧版本的 CHANGE MASTER TO)语句中设置以下关键参数绕过主机名/IP 验证:

在从库执行配置时,必须显式添加SOURCE_SSL_VERIFY_SERVER_CERT = 0(旧版本为 MASTER_SSL_VERIFY_SERVER_CERT = 0)。

如果主从已启用 GTID,我们不需要指定具体的 SOURCE_LOG_FILE 和 SOURCE_LOG_POS,只需重置源并指定 SSL 参数,按以下步骤进行:
-- (1). 停止复制
STOP REPLICA;

-- (2). 重置源配置(清除旧的明文配置)
RESET REPLICA ALL;

-- (3). 配置新的源,显式指定 SSL 参数
CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '192.168.1.111',
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '239131',
SOURCE_PORT = 3306,
SOURCE_AUTO_POSITION = 1,
SOURCE_SSL = 1,
SOURCE_SSL_CA = '/etc/mysql/ssl_client/ca.pem',
SOURCE_SSL_VERIFY_SERVER_CERT = 0; #如果是等保,则需要设置为1,且只能使用openssl生成证书

如果没有使用GTID,则需要指定具体的 SOURCE_LOG_FILE 和 SOURCE_LOG_POS

CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '主库IP',
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '密码',
SOURCE_SSL = 1,
SOURCE_SSL_CA = '/etc/mysql/ca.pem', -- 与主库 ssl_ca 同一份文件
SOURCE_LOG_FILE = 'mysql-bin.000001', -- 保持原来 binlog 位置
SOURCE_LOG_POS = 154;
SOURCE_SSL_VERIFY_SERVER_CERT = 0;

如果使用的是较老版本的 MySQL 8.0 (<8.0.22),请使用 CHANGE MASTER TO 语法,参数名为 MASTER_SSL=1, MASTER_SSL_CA='...' 等
11.启动复制(从库)
1
START REPLICA;
12.检查复制状态(从库)
1
SHOW REPLICA STATUS\G

关键字段必须是:

  • Slave_IO_Running: Yes
  • Slave_SQL_Running: Yes
  • Master_SSL_Allowed: Yes
  • Master_SSL_Cipher 非空(显示具体加密算法,如 ECDHE-ECDSA-AES256-SHA384)

如果 Master_SSL_Allowed: No,说明 SSL 参数没传全,复制已静默回退到明文。

如果 Master_SSL_Allowed 为 No 或 Master_SSL_Cipher 为空,说明连接未加密,需检查从库的 CHANGE REPLICATION SOURCE TO 语句是否正确执行。

辟坑指南:

  • ‌证书权限不对‌:server-key.pem 不是 600 权限时,MySQL 启动会静默忽略 SSL 配置,Ssl_cipher 始终为空
  • ‌CA 不一致‌:从库 SOURCE_SSL_CA 必须和主库 ssl_ca 是同一份文件,否则报 SSL error: certificate verify failed
  • ‌SELinux 拦截‌:日志出现 SSL_CTX_set_default_verify_paths failed,可临时 sudo setenforce 0 验证,长期需打 SELinux 策略
  • ‌证书 CN 不匹配‌:证书 CN/SAN 必须包含主库实际访问的 IP 或域名,否则 X509_V_ERR_IP_ADDRESS_MISMATCH
  • **客户端连接报错 certificate verify failed**‌:多半是连接的主机名和证书 CN/SAN 不匹配,自签名证书默认只含 localhost 和 127.0.0.1,连 IP 要重新生成证书。
  • ‌**Java 程序连接报 Path does not chain**‌:需要把 ca.pem 导入 Java 的信任库(keytool -importcert)。
  • ‌SELinux 拦截‌:日志出现 SSL_CTX_set_default_verify_paths failed 时,需要调整文件上下文或临时 setenforce 0 排查。

三、Openssl生成ssl证书

OPenssl配置ssl与mysql_ssl_rsa_setup的流程大体一致,以下仅列出不同之处

1.生成ssl证书(主库和从库)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
🔹1.创建证书目录(建议与MySQL数据目录分离)
mkdir -p /etc/mysql/ssl
chown mysql:mysql /etc/mysql/ssl
cd /etc/mysql/ssl

🔹2.生成 CA 私钥和证书
openssl genrsa -out ca-key.pem 2048
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca.pem -subj "/CN=MySQL_CA"

🔹3.生成服务器私钥和证书请求
openssl genrsa -out server-key.pem 2048
openssl req -new -key server-key.pem -out server-req.csr -subj "/CN=localhost"

🔹4.创建扩展配置文件,指定 SAN 覆盖 localhost 和 127.0.0.1
cat > extfile.cnf <<EOF
subjectAltName = DNS:localhost,IP:127.0.0.1
EOF

cat > extfile.cnf <<EOF
subjectAltName = DNS:localhost,IP:192.168.1.111
EOF


🔹5.用 CA 签发服务器证书
openssl x509 -req -in server-req.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 3650 -extfile extfile.cnf

🔹6.生成客户端私钥和证书请求
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem

Generating a 2048 bit RSA private key
...................................+++
...........................+++
writing new private key to 'client-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:GD
Locality Name (eg, city) [Default City]:GZ
Organization Name (eg, company) [Default Company Ltd]:HYJK
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:192.168.1.111
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

🔹7.用 CA 签发客户端证书
openssl x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem

🔹8.授权:
chown -R mysql.mysql *.pem
chmod 600 *key.pem

🔹9.查看证书
[root@slave01 ~]# openssl x509 -in /etc/mysql/ssl/ca.pem -text -noout

🔹10. 验证证书
openssl verify -CAfile ca.pem server-cert.pem client-cert.pem

openssl x509 -in server-cert.pem -noout -text | grep -A1 "Subject Alternative Name"
X509v3 Subject Alternative Name:
DNS:localhost, IP Address:192.168.1.111

🔹11.测试连接:
# mysql -utest -p -h localhost --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-mode=VERIFY_CA
# mysql -utest -p -h localhost --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-mode=VERIFY_IDENTITY
# mysql -utest -p -h 127.0.0.1 --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-mode=VERIFY_IDENTITY

ℹ️温馨提示:
从库配置SSL,Common Name填写192.168.1.121
CA 证书的 Common Name(CN)必须与服务器、客户端证书的 CN 不同,否则 OpenSSL 编译的 MySQL 会报错 ERROR 2026 (HY000): SSL connection error


参考:
第一步:创建根证书颁发机构 (Root CA)
🔹生成 CA 私钥
openssl genrsa -out ca.key 4096
建议使用 4096 位 RSA 密钥以提高安全性。

🔹生成 CA 根证书(自签名)
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=MyRootCA"
-x509:表示生成自签名证书。
-days 3650:有效期 10 年。
ca.crt 将作为信任根,分发到所有客户端(如浏览器、从库服务器)。

第二步:生成服务器证书请求 (CSR)
🔹生成服务器私钥
openssl genrsa -out server.key 2048
🔹生成证书签名请求 (CSR)
openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=db.example.com"
注意:CN (Common Name) 必须填写服务器的域名或 IP 地址。如果需要通过 IP 访问,建议在下一步添加 SAN (Subject Alternative Name)。

第三步:使用 CA 签发服务器证书
为了支持现代浏览器和 MySQL 8.0+ 的严格校验,建议添加 ‌SAN (主题备用名称)‌。
🔹创建扩展配置文件 (ext.cnf)
创建一个名为 ext.cnf 的文件,内容如下:
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = db.example.com
IP.1 = 192.168.1.100

将 DNS.1 和 IP.1 替换为你实际的域名和 IP。

🔹签发证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256 -extfile ext.cnf

-CAcreateserial:自动生成序列号文件。
-extfile ext.cnf:应用 SAN 扩展配置。

第四步:验证证书
# 验证服务器证书是否由 CA 签发
openssl verify -CAfile ca.crt server.crt
如果输出 server.crt: OK,则证书链有效。

方案二:快速生成自签名证书(仅用于测试)
如果你不需要 CA 层级,只需一个快速可用的证书(例如本地开发测试),可以使用单条命令生成。
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -subj "/CN=localhost"

-nodes:不对私钥进行密码保护(方便自动化部署,但安全性较低)。
此证书没有经过第三方 CA 签名,客户端连接时会报“不受信任”警告,需手动忽略或导入信任。

ℹ️温馨提示:

CN 与 SAN 匹配:
MySQL 8.0.23+ 和现代浏览器强制校验 SAN。如果证书中只有 CN 而没有 SAN,或者 SAN 中的 IP/域名与连接地址不一致,连接会失败。务必使用 ext.cnf 方式生成包含 SAN 的证书。

CA 证书分发:
在自建 CA 场景中,客户端(如 MySQL 从库、浏览器)必须信任 ca.crt。

MySQL 从库:在 CHANGE REPLICATION SOURCE TO 中指定 SOURCE_SSL_CA = '/path/to/ca.crt'。
Linux 系统:可将 ca.crt 复制到 /usr/local/share/ca-certificates/ 并运行 update-ca-certificates。
有效期:
自签名证书和 CA 证书都有有效期。生产环境建议设置合理的有效期(如 1 年),并建立证书轮换机制。
2.从库连接主库测试ssl连接(从库)
1
# mysql -urepl -p -h192.168.1.111 --ssl-ca=/etc/mysql/ssl_client/ca.pem --ssl-mode=VERIFY_IDENTITY 
3.change replicatioin source to
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '主库IP',
SOURCE_USER = 'repl_user',
SOURCE_PASSWORD = 'StrongPassword123!',
SOURCE_PORT = 3306,
SOURCE_LOG_FILE = 'mysql-bin.0000xx', -- 替换为当前主库 binlog 文件
SOURCE_LOG_POS = xxxxxx, -- 替换为当前主库 binlog 位置
SOURCE_SSL = 1, -- 启用 SSL
SOURCE_SSL_CA = '/var/lib/mysql/ca.pem', -- 指向从库本地的 CA 证书路径
SOURCE_SSL_CERT = '/var/lib/mysql/client-cert.pem', -- 客户端证书
SOURCE_SSL_KEY = '/var/lib/mysql/client-key.pem', -- 客户端私钥
SOURCE_SSL_VERIFY_SERVER_CERT = 1; -- 【等保关键】验证服务器证书

CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '主库IP',
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '密码',
SOURCE_SSL = 1,
SOURCE_SSL_CA = '/etc/mysql/ca.pem', -- 与主库 ssl_ca 同一份文件
SOURCE_SSL_CERT = '/etc/mysql/client-cert.pem', -- 建议带上
SOURCE_SSL_KEY = '/etc/mysql/client-key.pem', -- 建议带上
SOURCE_LOG_FILE = 'mysql-bin.000001', -- 保持原来 binlog 位置
SOURCE_LOG_POS = 154;

如果使用的是较老版本的 MySQL 8.0 (<8.0.22),请使用 CHANGE MASTER TO 语法,参数名为 MASTER_SSL=1, MASTER_SSL_CA='...' 等。

如果主从已启用 GTID,我们不需要指定具体的 SOURCE_LOG_FILE 和 SOURCE_LOG_POS,只需重置源并指定 SSL 参数,按以下步骤进行:
-- (1). 停止复制
STOP REPLICA;

-- (2). 重置源配置(清除旧的明文配置)
RESET REPLICA ALL;

-- (3). 配置新的源,显式指定 SSL 参数
CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '主库IP',
SOURCE_USER = 'repl_user',
SOURCE_PASSWORD = 'StrongPassword123!',
SOURCE_PORT = 3306,
SOURCE_AUTO_POSITION = 1, -- 启用 GTID 自动定位
SOURCE_SSL = 1, -- 启用 SSL
SOURCE_SSL_CA = '/var/lib/mysql/ca.pem', -- 从库本地的 CA 路径
SOURCE_SSL_CERT = '/var/lib/mysql/client-cert.pem', -- 从库本地的客户端证书
SOURCE_SSL_KEY = '/var/lib/mysql/client-key.pem', -- 从库本地的客户端私钥
SOURCE_SSL_VERIFY_SERVER_CERT = 1; -- 【等保关键】验证主库证书身份,防中间人攻击

CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '192.168.1.111',
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '239131',
SOURCE_PORT = 3306,
SOURCE_AUTO_POSITION = 1,
SOURCE_SSL = 1,
SOURCE_SSL_CA = '/etc/mysql/ssl/ca.pem',
SOURCE_SSL_CERT = '/etc/mysql/ssl/client-cert.pem',
SOURCE_SSL_KEY = '/etc/mysql/ssl/client-key.pem',
SOURCE_SSL_VERIFY_SERVER_CERT = 1;

-- 4. 启动复制
START REPLICA;
  • Title: Mysql配置ssl证书
  • Author: 𝓓𝓸𝓷
  • Created at : 2026-10-15 16:48:08
  • Updated at : 2026-10-15 17:49:06
  • Link: https://www.zhangdong.me/mysql_configuration_ssl_certificate.html
  • License: This work is licensed under CC BY-NC-SA 4.0.
评论