外观
MySQL SSL/TLS配置
SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是用于在网络通信中提供加密和身份验证的安全协议。在MySQL中启用SSL/TLS可以:
- 加密客户端和服务器之间的通信数据
- 验证服务器的身份,防止中间人攻击
- 可选地验证客户端身份
- 满足合规性要求(如PCI DSS)
证书生成
1. 使用自签名证书
自签名证书适合测试环境或内部使用,不适合生产环境。
生成CA证书
bash# 创建CA私钥 openssl genrsa 2048 > ca-key.pem # 生成CA证书 openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem生成服务器证书
bash# 生成服务器私钥 openssl genrsa 2048 > server-key.pem # 生成证书签名请求(CSR) openssl req -new -key server-key.pem -out server-req.pem # 生成服务器证书 openssl x509 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem生成客户端证书
bash# 生成客户端私钥 openssl genrsa 2048 > client-key.pem # 生成客户端CSR openssl req -new -key client-key.pem -out client-req.pem # 生成客户端证书 openssl x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem转换证书格式
bash# 转换服务器私钥为PEM格式 openssl rsa -in server-key.pem -out server-key.pem # 转换客户端私钥为PEM格式 openssl rsa -in client-key.pem -out client-key.pem
2. 使用商业CA证书
生产环境建议使用受信任的商业CA颁发的证书。
获取证书
- 从商业CA(如DigiCert、Let's Encrypt等)申请证书
- 按照CA提供商的指示生成CSR并获取证书
- 确保证书链完整
证书文件
- 服务器证书(.pem格式)
- 服务器私钥(.pem格式)
- CA证书链(.pem格式)
服务器配置
1. 基本配置
配置文件修改
ini[mysqld] # SSL配置 ssl-ca=/path/to/ca.pem ssl-cert=/path/to/server-cert.pem ssl-key=/path/to/server-key.pem # 强制所有连接使用SSL # require_secure_transport=ON # 可选:只允许特定加密协议 # ssl-cipher=TLSv1.2,TLSv1.3重启MySQL服务
bash# systemd系统 systemctl restart mysqld # SysV init系统 service mysqld restart
2. 验证SSL配置
检查SSL是否启用
sqlSHOW VARIABLES LIKE '%ssl%';预期输出
sql+---------------------+---------------------------+ | Variable_name | Value | +---------------------+---------------------------+ | have_ssl | YES | | ssl_ca | /path/to/ca.pem | | ssl_cert | /path/to/server-cert.pem | | ssl_key | /path/to/server-key.pem | | ssl_version | TLSv1.2,TLSv1.3 | +---------------------+---------------------------+
3. 用户权限配置
创建要求SSL的用户
sql-- 创建用户并要求SSL CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL; -- 创建用户并要求特定客户端证书 CREATE USER 'cert_user'@'%' IDENTIFIED BY 'password' REQUIRE X509; -- 授予权限 GRANT ALL PRIVILEGES ON *.* TO 'ssl_user'@'%'; GRANT ALL PRIVILEGES ON *.* TO 'cert_user'@'%'; -- 刷新权限 FLUSH PRIVILEGES;查看用户SSL要求
sqlSELECT user, host, ssl_type FROM mysql.user WHERE user IN ('ssl_user', 'cert_user');
客户端配置
1. 基本连接配置
使用命令行客户端连接
bash# 基本SSL连接 mysql -u ssl_user -p -h hostname --ssl # 使用特定证书连接 mysql -u cert_user -p -h hostname \ --ssl-ca=/path/to/ca.pem \ --ssl-cert=/path/to/client-cert.pem \ --ssl-key=/path/to/client-key.pem验证连接是否使用SSL
sqlSHOW STATUS LIKE 'Ssl_cipher';预期输出
sql+---------------+--------------------+ | Variable_name | Value | +---------------+--------------------+ | Ssl_cipher | TLS_AES_256_GCM_SHA384 | +---------------+--------------------+
2. 应用程序连接配置
PHP PDO配置
php$dsn = "mysql:host=hostname;dbname=database;charset=utf8mb4"; $options = [ PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem', PDO::MYSQL_ATTR_SSL_CERT => '/path/to/client-cert.pem', PDO::MYSQL_ATTR_SSL_KEY => '/path/to/client-key.pem', PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true ]; $pdo = new PDO($dsn, 'ssl_user', 'password', $options);Java JDBC配置
javaString url = "jdbc:mysql://hostname:3306/database?useSSL=true&requireSSL=true&verifyServerCertificate=true&trustCertificateKeyStoreUrl=file:/path/to/truststore.jks&trustCertificateKeyStorePassword=password"; Connection conn = DriverManager.getConnection(url, "ssl_user", "password");Python MySQL Connector配置
pythonimport mysql.connector config = { 'user': 'ssl_user', 'password': 'password', 'host': 'hostname', 'database': 'database', 'ssl_ca': '/path/to/ca.pem', 'ssl_cert': '/path/to/client-cert.pem', 'ssl_key': '/path/to/client-key.pem' } conn = mysql.connector.connect(**config)
3. 连接池配置
HikariCP配置
properties# HikariCP SSL配置 spring.datasource.hikari.data-source-properties.useSSL=true spring.datasource.hikari.data-source-properties.requireSSL=true spring.datasource.hikari.data-source-properties.verifyServerCertificate=true spring.datasource.hikari.data-source-properties.sslCA=/path/to/ca.pem spring.datasource.hikari.data-source-properties.sslCert=/path/to/client-cert.pem spring.datasource.hikari.data-source-properties.sslKey=/path/to/client-key.pemDruid配置
properties# Druid SSL配置 spring.datasource.druid.url=jdbc:mysql://hostname:3306/database?useSSL=true&requireSSL=true&verifyServerCertificate=true spring.datasource.druid.username=ssl_user spring.datasource.druid.password=password spring.datasource.druid.connection-properties=sslCA=/path/to/ca.pem;sslCert=/path/to/client-cert.pem;sslKey=/path/to/client-key.pem
不同MySQL版本的差异
MySQL 5.7 vs 8.0
默认配置差异
- MySQL 5.7:默认不启用SSL
- MySQL 8.0:默认启用SSL(使用自签名证书)
加密协议支持
- MySQL 5.7:支持TLSv1, TLSv1.1, TLSv1.2
- MySQL 8.0:支持TLSv1, TLSv1.1, TLSv1.2, TLSv1.3(默认禁用TLSv1, TLSv1.1)
证书管理
- MySQL 8.0:新增了
mysql_ssl_rsa_setup工具,简化证书生成 - MySQL 8.0:支持动态修改SSL配置(无需重启服务)
- MySQL 8.0:新增了
MySQL 8.0 小版本差异
TLSv1.3支持
- MySQL 8.0.16+:正式支持TLSv1.3
- MySQL 8.0.26+:默认启用TLSv1.3
加密算法
- 后续版本新增了更多安全的加密算法
- 移除了一些不安全的加密算法
性能考虑
1. 加密对性能的影响
- CPU开销:加密和解密操作会增加CPU负载,通常增加5-15%
- 网络带宽:加密数据会增加数据大小,通常增加5-10%
- 连接建立时间:SSL握手会增加连接建立时间
2. 性能优化建议
- 使用硬件加速:确保CPU支持AES-NI指令集,提高加密性能
- 合理配置加密协议:只启用安全的加密协议(如TLSv1.2, TLSv1.3)
- 优化连接池:增加连接池大小,减少连接建立频率
- 选择性加密:只对敏感数据或外部连接使用SSL
安全最佳实践
1. 证书管理
- 定期更新证书:证书到期前及时更新
- 安全存储私钥:限制私钥文件的访问权限(chmod 600)
- 使用强密码保护私钥
- 建立证书撤销机制
2. 配置最佳实践
- 禁用不安全的协议:只启用TLSv1.2和TLSv1.3
- 使用强加密算法:如AES-256-GCM, CHACHA20-POLY1305
- 强制敏感用户使用SSL
- 定期检查SSL配置:使用工具如
openssl s_client检查SSL配置
3. 监控和审计
监控SSL连接数:
sqlSHOW GLOBAL STATUS LIKE 'Ssl%';审计SSL连接:
sql-- 启用审计日志 SET GLOBAL audit_log=ON; SET GLOBAL audit_log_format=JSON;
常见问题(FAQ)
Q1: MySQL 8.0默认启用SSL,如何禁用?
A1: 可以通过修改配置文件禁用SSL:
ini
[mysqld]
skip_ssl然后重启MySQL服务。
Q2: 如何检查MySQL服务器支持的SSL加密算法?
A2: 使用openssl s_client工具:
bash
openssl s_client -connect hostname:3306 -tls1_2 < /dev/null 2>/dev/null | grep -A 10 "Cipher Suites"Q3: 客户端连接时出现"SSL connection error: SSL_CTX_set_default_verify_paths failed"怎么办?
A3: 这个错误通常是因为客户端找不到CA证书。解决方法:
- 确保指定了正确的CA证书路径
- 使用
--ssl-ca参数指定CA证书 - 对于自签名证书,可以使用
--ssl-mode=VERIFY_CA或--ssl-mode=VERIFY_IDENTITY
Q4: 如何配置MySQL复制使用SSL?
A4: 配置主从复制使用SSL的步骤:
- 确保主库和从库都已启用SSL
- 在主库创建复制用户并要求SSL:sql
CREATE USER 'repl'@'%' IDENTIFIED BY 'password' REQUIRE SSL; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; - 在从库配置复制连接:sql
CHANGE MASTER TO MASTER_HOST='master_host', MASTER_USER='repl', MASTER_PASSWORD='password', MASTER_SSL=1, MASTER_SSL_CA='/path/to/ca.pem', MASTER_SSL_CERT='/path/to/client-cert.pem', MASTER_SSL_KEY='/path/to/client-key.pem';
Q5: 如何验证客户端连接确实使用了SSL?
A5: 在MySQL客户端中执行:
sql
SHOW STATUS LIKE 'Ssl_cipher';如果返回非空值,表示连接使用了SSL。
Q6: MySQL SSL配置后,性能下降明显怎么办?
A6: 可以尝试以下优化措施:
- 确保CPU支持AES-NI硬件加速
- 升级到MySQL 8.0,享受更好的SSL性能
- 只对外部连接或敏感用户启用SSL
- 优化连接池配置,减少连接建立频率
- 使用更高效的加密算法,如TLSv1.3
Q7: 如何使用Let's Encrypt证书配置MySQL SSL?
A7: 步骤如下:
- 使用Certbot获取Let's Encrypt证书
- 将证书复制到MySQL配置目录
- 修改MySQL配置文件:ini
[mysqld] ssl-ca=/etc/letsencrypt/live/example.com/chain.pem ssl-cert=/etc/letsencrypt/live/example.com/cert.pem ssl-key=/etc/letsencrypt/live/example.com/privkey.pem - 重启MySQL服务
Q8: MySQL 5.7如何启用TLSv1.3?
A8: MySQL 5.7不支持TLSv1.3,需要升级到MySQL 8.0.16或更高版本才能使用TLSv1.3。
故障排查
1. 常见错误及解决方法
错误1:"SSL connection error: certificate verify failed"
- 原因:客户端无法验证服务器证书
- 解决方法:确保客户端信任服务器证书,或使用
--ssl-mode=DISABLED临时绕过验证
错误2:"SSL connection error: wrong version number"
- 原因:客户端和服务器使用的SSL协议版本不匹配
- 解决方法:指定正确的SSL协议版本,如
--ssl-version=TLSv1.2
错误3:"Access denied for user 'user'@'host' (using password: YES)"
- 原因:用户要求SSL但连接未使用SSL
- 解决方法:确保客户端连接时使用了
--ssl参数
2. 诊断工具
openssl s_client:检查服务器SSL配置
bashopenssl s_client -connect hostname:3306 -tls1_2mysql_ssl_rsa_setup:生成SSL证书(MySQL 5.7+)
bashmysql_ssl_rsa_setup --datadir=/path/to/dataSHOW VARIABLES:查看MySQL SSL配置
sqlSHOW VARIABLES LIKE '%ssl%';
