跨公網進行 MySQL 複寫時,資料以明文傳輸極易被竊聽或竄改。啟用 SSL/TLS 不僅能加密複寫流量,透過雙向憑證驗證還能防止暴力破解與中間人攻擊。本文完整記錄從 OpenSSL 安裝、CA 建立、伺服器/客戶端憑證簽發、MySQL 配置到複寫啟動的全流程,並針對常見錯誤(時間不同步、權限錯誤、憑證路徑錯誤)給出解決方案。
# 建議使用系統套件管理器安裝,避免手動編譯版本不一致 yum install -y openssl openssl-devel # CentOS/RHEL apt-get install -y openssl libssl-dev # Debian/Ubuntu
驗證版本:openssl version 應為 1.1.1 或 3.0+(支援 TLS 1.2/1.3)。
SHOW VARIABLES LIKE '%ssl%';
若 have_ssl、have_openssl 顯示 DISABLED,需確認編譯參數 -DWITH_SSL=system 或安裝官方 RPM/DEB(已內建 SSL)。
[mysqld] ssl=ON ssl_ca=/etc/mysql/ssl/ca.pem ssl_cert=/etc/mysql/ssl/server-cert.pem ssl_key=/etc/mysql/ssl/server-key.pem [client] ssl=ON ssl_ca=/etc/mysql/ssl/ca.pem ssl_cert=/etc/mysql/ssl/client-cert.pem ssl_key=/etc/mysql/ssl/client-key.pem
重啟 MySQL 後再次執行 SHOW VARIABLES LIKE '%ssl%',應顯示 YES。
所有操作在 **主庫** 執行,完成後將對應檔案分發至從庫。
mkdir -p /etc/mysql/ssl/{certs,crl,newcerts,private}
touch /etc/mysql/ssl/index.txt
echo 01 > /etc/mysql/ssl/serial
echo 01 > /etc/mysql/ssl/crlnumber
# 私鑰 4096 bits,有效期 10 年 (umask 077; openssl genrsa -out /etc/mysql/ssl/private/ca-key.pem 4096) openssl req -new -x509 -key /etc/mysql/ssl/private/ca-key.pem \ -out /etc/mysql/ssl/certs/ca.pem -days 3650 \ -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=DBA/CN=MySQL-CA"
# 主庫 openssl genrsa -out /etc/mysql/ssl/private/server-key.pem 2048 openssl req -new -key /etc/mysql/ssl/private/server-key.pem \ -out /etc/mysql/ssl/certs/server-req.pem \ -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=DBA/CN=mysql-master" openssl x509 -req -in /etc/mysql/ssl/certs/server-req.pem \ -CA /etc/mysql/ssl/certs/ca.pem -CAkey /etc/mysql/ssl/private/ca-key.pem \ -CAcreateserial -out /etc/mysql/ssl/certs/server-cert.pem -days 365 -sha256 # 從庫(CN 不同) openssl genrsa -out /etc/mysql/ssl/private/client-key.pem 2048 openssl req -new -key /etc/mysql/ssl/private/client-key.pem \ -out /etc/mysql/ssl/certs/client-req.pem \ -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=DBA/CN=mysql-slave" openssl x509 -req -in /etc/mysql/ssl/certs/client-req.pem \ -CA /etc/mysql/ssl/certs/ca.pem -CAkey /etc/mysql/ssl/private/ca-key.pem \ -CAcreateserial -out /etc/mysql/ssl/certs/client-cert.pem -days 365 -sha256
openssl verify -CAfile /etc/mysql/ssl/certs/ca.pem \ /etc/mysql/ssl/certs/server-cert.pem /etc/mysql/ssl/certs/client-cert.pem
chown -R mysql:mysql /etc/mysql/ssl chmod 600 /etc/mysql/ssl/private/*.pem chmod 644 /etc/mysql/ssl/certs/*.pem # 將 ca.pem、client-cert.pem、client-key.pem 複製到從庫相同路徑 scp /etc/mysql/ssl/certs/ca.pem /etc/mysql/ssl/certs/client-cert.pem /etc/mysql/ssl/private/client-key.pem slave:/etc/mysql/ssl/
CREATE USER 'repl'@'%' IDENTIFIED BY 'ReplPassw0rd!' REQUIRE SSL; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;
# 主庫:取得 binlog 位置 FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS; # 記下 File 與 Position,例如 mysql-bin.000007, 1015 UNLOCK TABLES; # 使用 xtrabackup 或 mysqldump 完整備份並傳輸至從庫 # 從庫:還原資料、設定 server-id、relay-log 等
CHANGE MASTER TO MASTER_HOST='192.168.1.100', MASTER_USER='repl', MASTER_PASSWORD='ReplPassw0rd!', MASTER_LOG_FILE='mysql-bin.000007', MASTER_LOG_POS=1015, MASTER_SSL=1, MASTER_SSL_CA='/etc/mysql/ssl/certs/ca.pem', MASTER_SSL_CERT='/etc/mysql/ssl/certs/client-cert.pem', MASTER_SSL_KEY='/etc/mysql/ssl/private/client-key.pem', MASTER_SSL_VERIFY_SERVER_CERT=1; START SLAVE; SHOW SLAVE STATUS\G
關鍵欄位應顯示:Slave_IO_Running: Yes、Slave_SQL_Running: Yes、Master_SSL_Allowed: Yes。
| 錯誤訊息 | 原因 | 解決 |
|---|---|---|
SSL connection error: ASN: before date in the future | 主從伺服器系統時間不同步 | 安裝 chrony/ntpdate 強制同步:ntpdate pool.ntp.org |
Access denied for user 'repl'@'...' (using password: YES) | 未加 REQUIRE SSL 或憑證路徑錯誤 | 重建帳號加 REQUIRE SSL;檢查 MASTER_SSL_* 路徑與權限 |
SSL error: unable to get private key | 私鑰檔案權限非 600 或擁有者非 mysql | chown mysql:mysql /etc/mysql/ssl/private/*key.pem && chmod 600 /etc/mysql/ssl/private/*key.pem |
Master_SSL_Verify_Server_Cert: No | 未啟用伺服器憑證驗證 | 在 CHANGE MASTER TO 加入 MASTER_SSL_VERIFY_SERVER_CERT=1 |
# 從庫測試 SSL 連線 mysql -u repl -p -h 192.168.1.100 \ --ssl-ca=/etc/mysql/ssl/certs/ca.pem \ --ssl-cert=/etc/mysql/ssl/certs/client-cert.pem \ --ssl-key=/etc/mysql/ssl/private/client-key.pem \ -e "SHOW STATUS LIKE 'Ssl_cipher';" # 主庫查看複寫執行緒 SSL 狀態 SHOW PROCESSLIST; # 應看到 system user 執行緒的 Command 為 "Binlog Dump",且 Info 含有 SSL
結語: SSL 複寫不僅滿足合規需求,更是跨公網部署的基礎防線。建議搭配 require_secure_transport=ON 強制所有連線走 TLS,並定期輪換憑證(每年一次)。