如何用mysql_async创建MariaDB TLS连接?证书配置故障排查
Rust连接MariaDB 10.x的SSL证书配置问题
我用Rust连接MariaDB 10.x数据库,持有客户端证书、CA证书、客户端密钥三个文件,但始终无法建立连接。尝试了rustls-tls和native-tls两种TLS后端,各种SSL配置组合均失败,错误信息如下:
使用rustls-tls时的错误
called `Result::unwrap()` on an `Err` value: Io(Io(Custom { kind: InvalidData, error: InvalidCertificate(Other(UnsupportedCertVersion)) }))
called `Result::unwrap()` on an `Err` value: Io(Tls(Tls(InvalidCertificate(BadEncoding))))
使用native-tls时的错误
called `Result::unwrap()` on an `Err` value: Io(Tls(TlsError(Os { code: -2146893018, kind: Uncategorized, message: "The format of the received message was unexpected or incorrect." })))
called `Result::unwrap()` on an `Err` value: Io(Tls(TlsError(Os { code: -2146881269, kind: Uncategorized, message: "ASN1 Invalid license plate value." })))
尝试过的SSL配置组合
let ssl_opts = SslOpts::default() .with_danger_accept_invalid_certs(true) .with_client_identity(Some(ClientIdentity::new( Path::new("/src/ssl2/client-cert.pem"), Path::new("/src/ssl2/client-key.pem"), ))) .with_client_identity(Some(ClientIdentity::new( Path::new("/src/ssl2/ca-cert.pem"), Path::new("/src/ssl2/ca-key.pem"), ))) .with_client_identity(Some(ClientIdentity::new( Path::new("/src/ssl2/server-cert.pem"), Path::new("/src/ssl2/server-key.pem"), ))); let ssl_opts = SslOpts::default() .with_danger_accept_invalid_certs(true) .with_client_identity(Some( ClientIdentity::new(Path::new("/src/ssl2/client-identity.p12")) .with_password("Password"), )) .with_root_cert_path(Some(Path::new("/src/ssl2/client-cert.pem"))) .with_root_cert_path(Some(Path::new("/src/ssl2/client-key.pem"))) .with_root_cert_path(Some(Path::new("/src/ssl2/ca-cert.pem"))) .with_root_cert_path(Some(Path::new("/src/ssl2/ca-key.pem"))); let ssl_opts = SslOpts::default() .with_danger_accept_invalid_certs(true) .with_client_identity(Some( ClientIdentity::new(Path::new("/src/ssl2/client-identity.p12")) .with_password("Password"), ));
这些证书可正常用于MySQL Workbench和HeidiSQL,请问证书使用环节存在什么问题?
问题分析与解决思路
1. 核心配置错误
你之前的配置存在几个关键逻辑错误:
- 重复调用
with_client_identity:该方法是覆盖式设置,多次调用后仅最后一次配置生效,导致客户端身份被错误设置为server证书/密钥,完全不符合TLS身份验证逻辑。 - 混淆根证书与客户端证书:
with_root_cert_path仅需传入CA证书,你把客户端证书、密钥都传入,TLS后端会将这些非CA证书当作可信根证书解析,必然出现编码或格式错误。 - P12与PEM配置冗余:若已使用P12文件作为客户端身份,无需额外指定PEM格式的证书/密钥,冗余配置会干扰解析流程。
2. 正确配置示例
方式一:使用PEM格式证书(客户端证书+密钥+CA证书)
use std::path::Path; use mysql_async::SslOpts; let ssl_opts = SslOpts::default() // 仅测试用,生产环境禁止开启 .with_danger_accept_invalid_certs(true) // 设置客户端身份:客户端证书+客户端密钥 .with_client_identity(Some(mysql_async::ClientIdentity::new( Path::new("/src/ssl2/client-cert.pem"), Path::new("/src/ssl2/client-key.pem"), ))) // 设置可信根证书:仅传入CA证书 .with_root_cert_path(Some(Path::new("/src/ssl2/ca-cert.pem")));
方式二:使用P12格式客户端身份文件
确保P12文件包含客户端证书、密钥,若未内置CA证书则需单独指定:
use std::path::Path; use mysql_async::SslOpts; let ssl_opts = SslOpts::default() .with_danger_accept_invalid_certs(true) .with_client_identity(Some( mysql_async::ClientIdentity::new(Path::new("/src/ssl2/client-identity.p12")) .with_password("Password"), )) // 若P12未包含CA证书,需单独指定 .with_root_cert_path(Some(Path::new("/src/ssl2/ca-cert.pem")));
3. 证书格式排查
- 检查客户端密钥是否为未加密的PEM格式,rustls对加密密钥支持有限,若为加密密钥需先解密。
- 确认CA证书是标准PEM格式,无多余空白行或格式损坏。
- 针对rustls的
UnsupportedCertVersion错误:检查证书版本是否为X.509 v3,rustls不支持v1/v2版本证书,而MySQL Workbench可能兼容旧版本。
内容的提问来源于stack exchange,提问作者RunDosRun
相关产品推荐
相关产品推荐

