MySQL主从复制明文风险在于binlog网络传输未加密,Wireshark可直接捕获UPDATE等敏感语句;需主库启用require_secure_transport=ON、从库配置SOURCE_SSL=1及正确CA证书,并设SOURCE_SSL_VERIFY_SERVER_CERT=0绕过CN校验,通过performance_schema或tcpdump验证加密生效。

复制链路不加密时,binlog 传输明文暴露在哪
MySQL 主从复制默认走 TCP 明文,mysql-bin.000001 里的 DML/DDL 内容、甚至 SET PASSWORD 这类语句,只要网络中间有抓包(比如同机房交换机镜像、云厂商底层流量),就能被还原。不是“理论上可能”,而是 Wireshark 开箱即用就能看到 UPDATE users SET token=... 这种行。
关键点:SSL 加密的是 **复制协议层**(I/O 线程拉取 binlog 的连接),不是 mysqld 启动时的 --ssl-mode 参数,也不是客户端连主库的那条连接。
- 主库必须开启
require_secure_transport=ON(否则从库用非 SSL 连接也能连上) - 从库配置
CHANGE REPLICATION SOURCE TO ... SOURCE_SSL=1(8.0.22+ 语法;老版本用CHANGE MASTER TO ... MASTER_SSL=1) - 证书需由同一 CA 签发,且从库的
SOURCE_SSL_CA必须指向主库的 CA 证书(不是它自己的)
生成和分发证书的最小必要步骤
不用 openssl 自建 CA 也能跑通,但自签名证书在从库连主库时会报 SSL connection error: SSL is required but the server doesn’t support it —— 实际是证书校验失败,错误信息极具误导性。
推荐用 MySQL 自带的 mysql_ssl_rsa_setup 一次性生成服务端/客户端共用的 PEM 文件,再手动拆分:
- 主库只需
ca.pem、server-cert.pem、server-key.pem - 从库需要
ca.pem(验证主库身份)、client-cert.pem、client-key.pem(向主库证明自己) - 所有证书文件权限必须为
600,mysqld 启动用户要能读取,否则启动时报SSL error: Unable to get certificate from file
示例(主库 my.cnf):
ssl_ca = /etc/mysql/ssl/ca.pem<br>ssl_cert = /etc/mysql/ssl/server-cert.pem<br>ssl_key = /etc/mysql/ssl/server-key.pem<br>require_secure_transport = ON
从库 CHANGE REPLICATION SOURCE 命令的关键参数
容易漏掉 SOURCE_SSL_VERIFY_SERVER_CERT=0 导致同步卡住 —— 这不是安全妥协,而是因为 MySQL 的 SSL 验证逻辑会检查证书 CN 是否匹配 SOURCE_HOST,而你填的是 IP 或内网域名,证书里 CN 往往是 localhost 或空。
-
SOURCE_SSL=1:强制走 SSL(必须) -
SOURCE_SSL_CA:指向主库的ca.pem(不是从库自己的) -
SOURCE_SSL_CERT和SOURCE_SSL_KEY:填从库自己的 client 证书路径 -
SOURCE_SSL_VERIFY_SERVER_CERT=0:绕过 CN 匹配(生产环境若用真实域名+正确证书可设为 1)
执行后立刻查:SELECT * FROM performance_schema.replication_connection_configuration\G,确认 SSL_ALLOWED 是 YES,SSL_CA 字段非空。
验证加密是否真生效的两个硬指标
别只信 “IO_Running: Yes”,得看底层连接是否加密。最直接的方法是登录从库执行:SHOW PROCESSLIST,找到 I/O 线程那一行,看 State 列是否含 Waiting for master to send event 且 Host 列显示 xxx:xxxxx(带端口),然后在主库上执行:SELECT * FROM performance_schema.threads WHERE TYPE='FOREGROUND' AND PROCESSLIST_COMMAND='Binlog Dump';,检查 THREAD_OS_ID 对应的系统进程是否启用 SSL。
- 更简单:主库开 general_log,执行一条 INSERT,看日志里 binlog dump 流量是否变成乱码(明文时能看到完整 SQL)
- 网络层验证:在主库服务器抓包
tcpdump -i any port 3306 -w mysql.pcap,用 Wireshark 打开,过滤mysql协议,如果解不出 Query 包,说明加密生效 - 注意:
replica_sql_thread不加密(本地回放),只有replica_io_thread的网络链路加密
证书路径写错、权限不对、CA 文件版本不一致,这三类问题占实际故障的 90%,每次改完记得 STOP REPLICA; START REPLICA;,不要指望自动重连。











