ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQL SSL连接配置详解:useSSL、CA证书与密钥的实战指南

MySQL SSL连接配置详解:useSSL、CA证书与密钥的实战指南 1. useSSLtrue到底是什么一条连接在握手阶段经历了什么很多人一上来就配置useSSLtrue和ca证书但对这套参数背后的握手机制并不清楚导致出了问题只能瞎试。我先讲清楚几个概念后面排查问题会省很多力气。MySQL原生的数据传输在默认情况下是不加密的。客户端发出查询、服务端返回结果集这些数据包在网络上是明文。如果你的数据库和应用部署在同一台机器或者在一个完全可信的内网里风险不大但只要数据会跨交换机、跨机房甚至经过公网就存在被截获的可能。useSSLtrue就是告诉MySQL客户端驱动这条连接要启动TLS加密握手协商出一个会话密钥之后的数据包都走加密通道。但这里有个关键细节——连接串里写了useSSLtrue只是代表客户端愿意使用SSL并不代表服务端一定在用它。MySQL服务端如果自身没开启SSL支持客户端即使传了useSSLtrue部分驱动尤其是老版本JDBC驱动会静默降级回明文连接。这也是我在生产环境里最担心的情况你以为在加密实际在裸奔。所以业界有个共识光在客户端配不算完服务端也得确认开启了SSL账号最好再带上REQUIRE SSL这样的强制约束。1.1 单向验证与双向验证证书和密钥各司其职MySQL的SSL连接按验证强度可以分成两个档位单向验证只验服务端客户端拿到服务端的证书然后用自己信任的CA证书去校验这个证书是不是由该CA签发的。这个模式下客户端不需要提供自己的证书和私钥只需要一个CA证书作为信任锚点。双向验证客户端证书认证服务端除了发送自己的证书之外还会要求客户端出示证书和私钥并且服务端要用CA证书来验证客户端的证书是否可信。这个模式就是标题里说的配置ca证书和密钥连接的完整形态——不过严格讲单向验证只需要ca.pem双向验证才需要ca.pem、client-cert.pem、client-key.pem三件套。我在实际项目中见过不少团队把三件套一股脑全配上其实很多场景根本不需要双向。如果你只是担心数据被嗅探单向验证加加密传输已经足够如果你希望做到只有持有合法客户端证书的机器才能连上MySQL那才需要双向。这个选择的逻辑不复杂双向验证意味着证书的分发和管理成本翻倍。客户端证书一旦过期你所有应用都得跟着更新如果业务方是外部团队证书分发渠道还不一定顺畅。所以我的建议是默认先做单向验证有明确的安全合规要求再做双向。1.2 MySQL数据目录里的那些.pem文件分别是谁配置MySQL SSL时最让人头晕的就是MySQL数据目录下那一堆.pem文件。很多教程直接让你把整个目录的文件一股脑拷走其实每份文件角色完全不同。默认情况下MySQL安装完成后会自动生成一批证书常见的有文件名角色连接配置中的作用ca.pem自签CA证书客户端校验服务端证书的信任锚点单向验证必需server-cert.pem服务端证书服务端发给客户端、证明自己身份的证书server-key.pem服务端私钥服务端持有负责TLS握手时的签名/解密client-cert.pem客户端证书双向验证时客户端出示给服务端验证client-key.pem客户端私钥双向验证时客户端用于证明自己持有对应私钥public_key.pem公钥用于caching_sha2_password插件的RSA公钥传输跟SSL不是一回事看到这个表你应该就明白了一个常见误区网上很多人说配置ca证书和密钥连接直接把client-key.pem当成了那个密钥。严格来说如果你做的是双向验证确实需要客户端密钥如果你做单向验证那个密钥指的是服务端的server-key.pem你在客户端根本不需要碰它。另外有一类历史坑public_key.pem经常让人混淆。这个文件解决的是caching_sha2_password认证插件在非SSL连接时如何安全传输密码的问题。如果你连接报Public Key Retrieval is not allowed那是它的事跟useSSL、CA证书没有直接关系我后面会专门讲。2. 证书文件从哪来现成证书与自签CA的两种准备路径配置MySQL SSL的前置工作是确保你手里有一份可用的CA证书、一份服务端证书和对应的密钥。这里有两种路径一种是用MySQL自动生成的另一种是自己用OpenSSL整套签发。2.1 路径一直接用MySQL自动生成的证书文件这是最省事的方式。MySQL 5.7及以上版本安装并初始化数据目录时如果检测到SSL相关文件缺失会自动生成ca.pem、server-cert.pem等文件放在数据目录下。你可以直接查mysql -uroot -p -e SHOW VARIABLES LIKE datadir;拿到数据目录后进去看ls -l /var/lib/mysql/*.pem如果你在数据目录里能看到这些文件说明服务端已经具备了SSL能力。此时你只需要把ca.pem从服务器上拷贝下来放到客户端机器或者打包进应用的资源目录就行。这里有个实际部署中的细节用MySQL自动生成的CA证书和服务端证书有效期默认是十年很多团队配置完就不再管了。但一旦证书过期所有依赖它的客户端会同时断连那个排障过程会非常痛苦。所以从运维角度我建议你拿到证书文件后第一时间用OpenSSL看一眼有效期和证书指纹登记在一个表格里openssl x509 -in ca.pem -noout -dates -subject -fingerprint2.2 路径二用OpenSSL自建CA并签发服务端证书有些场景下你需要自定义证书的组织名称、有效期或者需要把同一套CA体系复用到多台服务器这时候MySQL自动生成的那份就不太够用了。自建CA的完整流程比较长我这边只提炼出核心步骤方便你直接参考。第一步生成CA私钥和自签CA证书openssl genrsa 2048 ca-key.pem openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem \ -subj /CNMyMySQLCA第二步生成服务端私钥和证书签名请求CSRopenssl req -newkey rsa:2048 -nodes -days 3650 \ -keyout server-key.pem -out server-req.pem \ -subj /CNmysql.server.example.com第三步用CA给服务端证书签名。这一步需要注意MySQL服务端证书的CN和实际主机名不匹配时客户端如果开了verifyServerCertificate校验会失败。所以签名时通常要带上SANSubject Alternative Name把IP和主机名都写进去openssl x509 -req -in server-req.pem -days 3650 \ -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem \ -extfile (printf subjectAltNameIP:127.0.0.1,DNS:localhost,DNS:mysql.server.example.com)这里有个经验MySQL自带的自动化脚本mysql_ssl_rsa_setup在新版本里虽然还在但我更建议用OpenSSL手动来因为后者可以看到完整的证书签发链条也更方便后期做轮换。2.3 客户端证书和密钥的签发如果你决定做双向验证再用同一套CA给客户端签发一份证书和密钥openssl req -newkey rsa:2048 -nodes -days 3650 \ -keyout client-key.pem -out client-req.pem \ -subj /CNmysql-client-app openssl x509 -req -in client-req.pem -days 3650 \ -CA ca.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem看清楚这里的密钥是client-key.pem真正的核心资产。私钥一旦泄露等于你发给客户端的通行证被人复制了。所以在分发的时候私钥文件的权限建议设置成只有运行用户可读chmod 600 client-key.pem3. 服务端启用SSL并配合用户账号做强制校验证书和私钥都准备好之后接下来要做的不是马上改客户端连接串而是先确认服务端确实在用SSL。这一步很多教程会跳过直接让你去改客户端——结果连不上时根本分不清是服务端没配好还是客户端参数错了。3.1 确认服务端当前SSL状态先用管理员账号登录MySQL执行SHOW VARIABLES LIKE %ssl%;正常输出中have_ssl应该是YESssl_ca、ssl_cert、ssl_key分别指向对应的证书文件路径。如果看到have_ssl是DISABLED或NO说明服务端还没开SSL。还有一种情况have_openssl是YEShave_ssl是DISABLED这通常是因为启动MySQL时没有加载ssl相关参数。此时需要编辑my.cnf。3.2 在配置文件中写入SSL参数并重启我一般会在[mysqld]段加上[mysqld] ssl-ca/etc/mysql/ssl/ca.pem ssl-cert/etc/mysql/ssl/server-cert.pem ssl-key/etc/mysql/ssl/server-key.pem需要注意两点第一证书目录的权限一定要收好。MySQL是以mysql用户身份运行的如果配置文件里的私钥文件其他用户也能读MySQL甚至会在启动时直接拒绝使用它。建议mkdir -p /etc/mysql/ssl cp ca.pem server-cert.pem server-key.pem /etc/mysql/ssl/ chown -R mysql:mysql /etc/mysql/ssl chmod 600 /etc/mysql/ssl/server-key.pem chmod 644 /etc/mysql/ssl/ca.pem /etc/mysql/ssl/server-cert.pem第二改完配置必须重启MySQL服务。重启前先校验配置是否正确mysqld --validate-config然后重启并再次执行SHOW VARIABLES LIKE %ssl%;确认状态变为YES。3.3 用REQUIRE SSL和REQUIRE X509限制账号服务端SSL能力开启后还需要在账号层面做约束否则普通账号仍然可以走明文连接。这也是我在开头提到的强制约束。REQUIRE SSL要求该账号只能通过加密连接登录但不校验客户端证书的合法性。REQUIRE X509要求客户端必须出示一个由受信任CA签发的有效证书同时连接必须加密。实际项目中如果是内部应用我倾向于用REQUIRE SSL因为客户端证书的分发、轮换成本高REQUIRE X509不适合快速迭代的业务。如果是面向外部合作方、敏感核心库才用REQUIRE X509。-- 要求普通内部应用账号必须走SSL ALTER USER app_user% REQUIRE SSL; -- 要求核心账号必须出示客户端证书 ALTER USER core_user% REQUIRE X509;这里有个小坑如果你用的是MySQL 8.0账号认证插件默认是caching_sha2_password在非SSL连接下第一次连接会要求额外获取RSA公钥。配好SSL之后这个问题会消失因为TLS已经提前保护了密码传输。所以如果你之前经常看到Public Key Retrieval is not allowed配置SSL也是一种解决路径。3.4 在线验证一下当前会话到底是不是加密的配置完成后用对应账号登录执行SHOW STATUS LIKE Ssl_cipher;如果有值输出比如TLS_AES_256_GCM_SHA384说明当前这条会话已经走了TLS加密。也可以在连接后执行\s查看SSL信息。这一步是很多教程不提但非常有用的验证手段能直接确认你一整条链路是通的。4. 客户端连接串的配置对照JDBC、命令行、Python与图形化工具服务端就绪后再看客户端。这部分我覆盖了最常见的四种接入方式Java JDBC、mysql命令行、Python、Navicat/Workbench。配置思路是一致的但各自的参数名和载体形式差别很大容易记混。4.1 Java JDBC连接串Java生态里连接MySQL通常用Connector/J。在8.0版本之前驱动名是com.mysql.jdbc.Driver8.0之后建议用com.mysql.cj.jdbc.Driver。SSL相关配置直接在JDBC URL上以参数形式拼进去。先看单向验证只校验服务端的完整URLString url jdbc:mysql://192.168.1.100:3306/appdb ?useSSLtrue verifyServerCertificatetrue requireSSLtrue trustCertificateKeyStoreUrlfile:/etc/ssl/mysql/myca.jks trustCertificateKeyStorePasswordchangeit;逐个参数解释一下useSSLtrue驱动启用SSL。不过Connector/J 8.0.x里这个参数已经被sslMode取代或弱化。新的写法建议直接写sslModeVERIFY_CA或sslModeVERIFY_IDENTITY。verifyServerCertificatetrue客户端用信任库中的CA证书去校验服务端证书。如果不写这个即使useSSLtrue也可能不会去验证证书身份存在中间人攻击风险。requireSSLtrue告诉驱动如果服务端不支持SSL就直接报错不要静默降级。trustCertificateKeyStoreUrl和trustCertificateKeyStorePassword指定Java信任库JKS或PKCS12格式的位置和密码这个信任库里必须已经导入了你的ca.pem。关于sslMode我简单提一下几个值DISABLED不加密、PREFERRED优先加密服务端不支持则降级、REQUIRED必须加密但只加密不验证证书、VERIFY_CA加密且用信任库验证服务端证书、VERIFY_IDENTITY在VERIFY_CA基础上进一步校验证书CN/SAN和主机名匹配。生产环境我建议至少用VERIFY_CA。双向验证的话还需要额外指定客户端证书String url jdbc:mysql://192.168.1.100:3306/appdb ?sslModeVERIFY_CA clientCertificateKeyStoreUrlfile:/etc/ssl/mysql/client.jks clientCertificateKeyStorePasswordchangeit trustCertificateKeyStoreUrlfile:/etc/ssl/mysql/myca.jks trustCertificateKeyStorePasswordchangeit;这里clientCertificateKeyStoreUrl指向的密钥库里面存的是客户端的私钥和公钥证书。连接时驱动会拿这份身份证明响应服务端的证书请求。4.2 mysql命令行和Python命令行连接是最直觉的方式参数直接用文件路径mysql -h 192.168.1.100 -u app_user -p \ --ssl-modeVERIFY_CA \ --ssl-ca/path/to/ca.pem如果是双向验证再加上mysql -h 192.168.1.100 -u core_user -p \ --ssl-modeVERIFY_CA \ --ssl-ca/path/to/ca.pem \ --ssl-cert/path/to/client-cert.pem \ --ssl-key/path/to/client-key.pem命令行模式--ssl-mode的可选值跟JDBC类似DISABLED、PREFERRED、REQUIRED、VERIFY_CA、VERIFY_IDENTITY。旧版本如果你只写--ssl-ca而不写--ssl-modeMySQL客户端会默认走PREFERRED也就是说不验证证书——你以为安全了其实没验证。Python这边最常用的pymysql在较新版本里通过ssl参数接收一个字典import pymysql conn pymysql.connect( host192.168.1.100, port3306, userapp_user, passwordyour_password, databaseappdb, ssl{ ca: /path/to/ca.pem, } )注意pymysql底层依赖Python的ssl模块。如果你要做双向验证需要额外加cert和key两个键ssl{ ca: /path/to/ca.pem, cert: /path/to/client-cert.pem, key: /path/to/client-key.pem, }不过要提醒一点pymysql的字典会原样透传给Python的ssl.SSLContext.load_verify_locations而Python的ssl模块通常不校验主机名所以连接时如果不是用IP直连你要确保证书里的CN和连接主机一致或者自己额外做校验。多数情况下用mysql-connector-python这种官方驱动反而封装得更完整SSL参数也更清晰。4.3 Navicat和MySQL Workbench图形化工具图形化工具虽然看着直观但SSL配置选项分散不少人卡在这里。MySQL Workbench里新建连接的SSL标签页中会有一个Use SSL下拉框里面有几档If Available优先用SSL没有则降级Require必须用SSL但不验证证书Verify CA用CA验证服务端证书Verify Identity验证CA且校验主机名选完Use SSL类型后填SSL CA File也就是ca.pem路径。如果做双向验证还要填SSL Cert File和SSL Key File。填完之后建议先点Test Connection确认实际协商的加密协议版本和TLS密码套件再保存连接。Navicat这边新建MySQL连接后在SSL标签页勾选Use SSL然后按需选择CA证书、客户端证书和客户端密钥。Navicat的优势是会把SSL状态直接显示在连接信息栏里连上之后一眼就能看到是不是TLS加密。有一个共同的坑Navicat和Workbench在不同操作系统上读证书文件权限会有差异。Windows上尤其容易遇到证书格式被识别为错误格式、或者文件被占用的情况。这时候先确认你拿到的ca.pem是PEM文本格式开头是-----BEGIN CERTIFICATE-----拒绝把.pem文件用记事本编辑后带上BOM头和多余换行——这个问题我在真实项目里踩过证书内容肉眼看着一样但解析就是失败。5. 证书配置中最容易翻车的三类报错与完整排查链路SSL配置报错几乎是每个人都会遇到的一道坎。问题表面千奇百怪底层原因就那几类。我把最常见的三个场景连同排查过程一起写出来你按照链路走一遍大部分问题都能定位。5.1 翻车场景一Java报PKIX path building failed这是Java应用使用自签CA证书时最经典的报错。完整报错通常长这样javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target问题本质JVM运行时的默认信任库cacerts里不包含你的自签CA证书。Java不像命令行客户端那样支持直接指定ca.pem文件路径它必须从一个KeyStore通常是JKS或PKCS12里去读信任证书。排查链路确认服务端证书确实由你的ca.pem签发openssl verify -CAfile ca.pem server-cert.pem。创建一个JKS信任库把ca.pem导入进去keytool -importcert -trustcacerts -alias mysql_ca \ -file ca.pem -keystore myca.jks -storepass changeit这里有个小细节keytool导入第一个证书时如果这台机器上以前导入过同名别名会报“证书已存在于系统安全库中”需要加-noprompt或者换个别名。真实的坑往往不是导入操作本身而是Java进程启动时没有加载这个信任库。确认JVM参数确实传了。在Spring Boot项目里通常这样做java -jar app.jar \ -Djavax.net.ssl.trustStore/etc/ssl/mysql/myca.jks \ -Djavax.net.ssl.trustStorePasswordchangeit还没完这里还要分清楚上面这个是JVM全局信任库。如果你在JDBC URL里写了trustCertificateKeyStoreUrl那JVM全局参数可以不用。两者并存时JDBC URL的优先级更高。所以排查时先确认你究竟在用哪一套不要两边各配了一半。5.2 翻车场景二命令行列SSL连接报2026错误命令行走--ssl-modeVERIFY_CA时最常见的报错是ERROR 2026 (HY000): SSL connection error: unable to get local issuer certificate这个报错出现时按顺序排查以下三件事第一--ssl-ca指向的路径对不对。很多人是从Windows上把ca.pem拷贝到Linux路径没同步自然找不到。这个相对好排查。第二证书链不完整。如果服务端证书不是由ca.pem直接签发而是一个中间CA签发的那客户端校验时需要整条证书链。这时需要在--ssl-ca里同时传入根CA和中间CA。可以这样拼接cat root-ca.pem intermediate-ca.pem combined-ca.pem mysql --ssl-cacombined-ca.pem ...第三证书内容在传输过程中被改动。最常见的是Windows和Linux之间通过FTP/记事本传输导致换行符被改、BOM头被加。这种情况下肉眼看不出区别但服务端每次都会报证书解析失败。解决办法是检查文件头部和尾部head -1 ca.pem | od -c如果看到357 273 277UTF-8 BOM说明带BOM了。重新拷贝一份用dos2unix处理一下通常就能解决。5.3 翻车场景三Public Key Retrieval is not allowed这个报错容易和SSL混在一起其实它本质上属于认证插件的问题。MySQL 8.0的默认认证插件是caching_sha2_password当客户端连接没有走SSL时驱动需要向服务端请求RSA公钥来加密密码但驱动默认不让这个请求于是报Public Key Retrieval is not allowed两个解决方向连接串上加allowPublicKeyRetrievaltrueJDBC或--get-server-public-key命令行允许驱动向服务端拿公钥。更稳妥的方式配置好SSL让整个认证过程在TLS保护下进行客户端根本不需要额外获取RSA公钥这个报错自然消失。所以我在实际处理这个报错时会先确认这条连接是不是真的已经走了SSL。如果走的是SSL这个报错理论上不该出现如果连接没有加密那配置SSL反而是更优雅的解法而不是把它当作一个独立参数绕过去。5.4 通用排查链路一竿子捅到底面对SSL连接失败我建议用下面这条固定链路排查不要跳跃在MySQL服务器本机用命令行连接确认服务端SSL正常mysql -h 127.0.0.1 -u app_user -p --ssl-modeVERIFY_CA --ssl-ca/path/to/ca.pem -e SHOW STATUS LIKE Ssl_cipher;如果这一步都失败问题一定在服务端证书或本机文件上。确认服务端证书有效期openssl x509 -in server-cert.pem -noout -dates。确认签发链openssl verify -CAfile ca.pem server-cert.pem。确认服务端启动配置SHOW VARIABLES LIKE %ssl%;看ssl_cert和ssl_key指向的文件是否存在、是否有权限读。客户端换一台干净的机器或者容器重新测试排除本地证书缓存、密钥库污染的问题。最后确认账号层面是否强制了SSL。如果某个账号是REQUIRE NONE它不会拒绝非SSL连接但如果连接中途报认证方式不兼容也可能误被当做SSL问题排查。6. 信任库的底层机制与几个实用建议过了排查关之后剩下的是对信任库机制的理解和日常运维建议。这部分内容不算特别难但理解得越透越能避免在证书轮换、多环境部署时出问题。6.1 Java信任库、系统证书库和自签CA的兼容三角Java应用的SSL校验依赖JVM的信任库。JVM默认信任的是JDK自带的cacerts里面预置了全球主流公共CA的根证书。但你自己的MySQL服务端证书是自签CA签发的这个自签CA不在cacerts里所以你必须把它导入到JVM信任库或者通过连接参数指定一个单独的信任库。这里有个容易混淆的点系统证书库比如Windows的证书管理器、Linux的/etc/ssl/certs和Java信任库是两套独立的体系。你在Windows上导入ca.pem到受信任的根证书颁发机构Navicat和Workbench能用但Java程序不一定能用。反过来你把ca.pem导入Java的cacerts系统命令行也不一定认。我在一个项目里曾看到同事把ca.pem导入了Windows系统证书库然后JDBC连接照样报PKIX错误他百思不得其解——其实就是没搞清楚Java信任库和系统证书库是两回事。6.2 导入CA到Java信任库的实际操作导入本身很简单但如果要对多套环境、多个JDK生效就需要一套相对规范的流程。我的做法是不直接改JDK自带的cacerts而是创建一个独立的信任库文件通过启动参数指定。这样不会污染公共JDK环境也方便不同项目使用不同CA。keytool -importcert -trustcacerts -alias mysql-dev-ca \ -file /opt/certs/ca.pem \ -keystore /opt/certs/mysql-truststore.jks \ -storepass changeit -noprompt如果应用里既有旧系统用JKS又有新系统偏好PKCS12建议干脆统一用PKCS12因为它是Java 9以后默认的KeyStore格式也是行业普遍认可的标准格式keytool -importcert -trustcacerts -alias mysql-dev-ca \ -file /opt/certs/ca.pem \ -keystore /opt/certs/mysql-truststore.p12 \ -storetype PKCS12 -storepass changeit -noprompt创建完信任库后启动参数里指定java -Djavax.net.ssl.trustStore/opt/certs/mysql-truststore.p12 \ -Djavax.net.ssl.trustStorePasswordchangeit \ -Djavax.net.ssl.trustStoreTypePKCS12 \ -jar app.jar有个细节值得注意如果你设置了JVM级信任库那么Java程序中所有依赖SSL的出站连接比如连接Redis、ES、外部API都会用这个信任库来校验对端证书。如果你的MySQL自签CA和某些公网API的证书不是同一套体系可能出现MySQL连上了但外部API握手失败的情况。所以更精细的做法是只在JDBC URL里指定不设置JVM全局。这也是为什么我在第4节里写了两个方案让读者按自己的实际环境选一个。6.3 证书轮换和双栈兼容的几个提醒证书配置完成后最容易被忽略的就是轮换。MySQL自动生成的证书和自签CA有效期一般都很长但你在生产环境里如果真等到过期那天再处理业务中断是不可避免的。轮换的推荐做法提前用OpenSSL生成好新证书不要等到最后一刻。先在服务端把新证书换上但要保留旧的CA证书同时受信任。MySQL 8.0支持指定多个CA证书文件比如把旧ca.pem和新ca.pem放在同一个目录服务端可以同时信任新旧两份。这样客户端可以分批切换不用某一个时间点全部断连。客户端信任库也同步导入新旧两份CA切换窗口就更从容。另外我建议服务端不要直接关闭非SSL连接[mysqld] # 不要设置 require_secure_transportON除非你确认所有客户端都已完成改造 require_secure_transportON如果强行开启require_secure_transportON而某个老应用连接串里忘了加useSSL参数它会在某个深夜突然全部连不上排障压力很大。稳妥的做法是先确认审计日志里所有客户端都已经走SSL再开启强制参数。可以用如下SQL查看当前连接是否加密SELECT user, host, ssl_type, ssl_cipher FROM performance_schema.session_status WHERE variable_name LIKE Ssl_cipher;确认没有问题之后再考虑开启强制加密。7. 从一次真实事故说起写错参数位置导致的半小时排障讲完上述内容我再说一个真实案例。之前有个开发环境应用突然连不上MySQL报错也是2026。现场同事已经把服务端SSL配置、客户端连接串都核对了一遍看起来没问题但还是不行。我到了现场先在服务器上执行SHOW VARIABLES LIKE %ssl%;看到ssl_cert指向的路径里文件确实存在。然后检查服务端日志看到一条比较隐蔽的警告无法加载SSL私钥文件因为权限过大。原来/etc/mysql/ssl/server-key.pem的权限是644MySQL出于安全策略拒绝加载世界可读的私钥。这个问题在服务端配置阶段就埋下了但因为当时MySQL自动生成的默认证书路径下权限是对的后来换成手动管理的证书目录时忘了收权限才导致服务端虽然显示ssl相关变量有值但实际上TLS握手失败。这个案例想说明的是SSL配置出问题时不要只盯着客户端参数服务端私钥权限、服务端证书文件数量、目录属主这类环境细节往往会带来更隐蔽的问题。所以我把权限这块在第3节里单独强调了一遍别看是小细节实盘环境最容易踩的就是这种小坑。另外还有一个常见的习惯问题很多团队把ca.pem和client-key.pem放在同一个目录甚至还会不小心提交到git仓库。客户端私钥一旦泄露你的双向认证就没有意义了。我给团队立的规矩是ca.pem属于公开信息可以放代码库client-key.pem只能通过密钥管理平台分发不允许进git也不允许写死在代码里。这个习惯比任何技术优化都重要。配置MySQL的useSSL和CA证书说难不难说简单也不简单。最核心的障碍往往不是某一步操作不会而是对整套Trust模型、密钥文件角色的理解不够清晰。把这个思路理顺了你不仅能顺畅地配起SSL连接遇到问题时也能做出相对准确的判断不至于全靠试错。
返回列表