You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

FireDAC TFDConnection启用SSL后程序挂起的排查方法及连接解决方案咨询

解决FireDAC连接MySQL SSL时程序挂起的问题

我之前也碰到过类似的FireDAC SSL连接卡住的情况,结合你描述的——TablePlus用相同证书正常、无SSL时FireDAC也正常,只在开SSL时挂起,大概率是参数配置细节或者FireDAC底层SSL处理的兼容性问题。下面是一步步的排查和解决方法:


1. 先确认证书的绝对路径

FireDAC对相对路径的处理可能不如TablePlus灵活,很可能因为找不到证书文件而无限等待(不是抛出错误)。你可以把证书路径改成绝对路径试试:

// 替换成你实际的证书路径,比如
conn.Params.Add('SSL_key=C:\your_certs\client-key.pem');
conn.Params.Add('SSL_ca=C:\your_certs\ca.pem');
conn.Params.Add('SSL_cert=C:\your_certs\client-cert.pem');

如果是要随程序部署,也可以用ExtractFilePath(ParamStr(0))拼接程序所在目录的路径,避免硬编码:

var
  CertPath: string;
begin
  CertPath := ExtractFilePath(ParamStr(0));
  conn.Params.Add('SSL_key=' + CertPath + 'client-key.pem');
  // 其他证书同理
end;

2. 检查SSL参数的完整性和正确性

FireDAC的MySQL SSL参数有几个容易忽略的点:

  • 私钥是否带密码:如果你的client-key.pem是加密的,FireDAC可能会默默等待输入密码(但没弹出提示),导致挂起。可以用OpenSSL命令验证:
    openssl rsa -in client-key.pem -check
    
    如果需要密码,得加上SSL_passphrase参数:
    conn.Params.Add('SSL_passphrase=你的私钥密码');
    
  • 强制SSL验证和指定版本:有些MySQL服务器只支持特定的TLS版本,或者需要严格验证服务器证书,试试添加:
    conn.Params.Add('SSL_verify_server_cert=True');
    conn.Params.Add('SSL_version=TLSv1.2'); // 或者TLSv1.3,根据服务器配置
    

3. 启用FireDAC日志,看卡在哪一步

FireDAC的日志能帮你精准定位问题,在连接前加上日志配置:

// 启用详细日志
FDManager.Logging := True;
FDManager.LogFileName := 'FireDAC_debug.log';
FDManager.LogOptions := [loAll];

运行程序到挂起后,终止进程打开日志文件,看最后几行的内容——通常会显示SSL握手的具体步骤,比如是在等待服务器响应,还是证书验证环节卡住了。

4. 设置连接超时,让错误提前暴露

默认的连接超时可能很长,导致看起来像挂起。设置短超时,让程序抛出明确的错误信息:

conn.Params.Add('ConnectTimeout=10'); // 10秒超时
conn.Params.Add('CommandTimeout=10');

如果超时后抛出错误,比如“SSL handshake timeout”或者“certificate verify failed”,就能直接定位问题方向。

5. 检查MySQL客户端库版本

FireDAC依赖libmysql.dll,如果这个库版本太旧,可能不支持服务器的SSL协议。建议下载与你的MySQL服务器版本匹配的最新稳定版libmysql.dll,放到程序目录或者系统PATH里。另外,旧版本的Delphi/FireDAC可能有SSL连接的bug,升级到最新版本或者安装FireDAC补丁也可能解决问题。

6. 简化配置逐步测试

先去掉多余的参数,只保留核心的SSL设置,看看能不能正常连接:

conn.Params.Clear;
conn.Params.DriverID := 'MySQL';
conn.Params.Add('Server='+serverAddress);
conn.Params.Database := databaseName;
conn.Params.UserName := userName;
conn.Params.Password := passWord;
conn.Params.Add('UseSSL=Required'); // 用Required强制SSL连接
conn.Params.Add('SSL_ca=ca.pem'); // 先只加CA证书,有些服务器只需要验证根证书
conn.LoginPrompt := False;

如果这样能连接,再逐步添加SSL_keySSL_cert,看看是哪个参数导致的挂起。


如果以上方法都不行,建议用Wireshark抓包,查看SSL握手的完整过程——是客户端发了Client Hello后没收到Server Hello,还是在证书交换阶段卡住了,结合抓包结果和FireDAC日志,就能快速找到问题根源。

内容的提问来源于stack exchange,提问作者Rando Hinn

火山引擎 最新活动