ssh隧道连不上数据库主因是本地端口被占或转发方向设错;需确认端口空闲、选对远程转发模式,并检查ssl配置、连接池及事务状态。

SSH 隧道连不上数据库,八成是 Local port 被占或转发方向写反
本地开发连生产库最常卡在这一步:明明 SSH 能通,psql 或客户端就是连不上 127.0.0.1:5432。核心就两点:本地监听端口是否空闲、隧道方向是否设成「远程端口转发」(Remote)而非「本地转发」(Local)。
实操建议:
- 先用
lsof -i :5432(macOS/Linux)或netstat -ano | findstr :5432(Windows)确认Local port没被其他进程占用 - DBeaver / DataGrip 里建连接时,SSH 设置页选的是
SSH Tunnel,不是SSH Config;Local port填你本地想用的端口(比如5433),Remote host填数据库真实地址(如10.10.20.5),Remote port填数据库实际端口(如5432) - TablePlus 里对应字段叫
Local Port和Remote Host/Port,别和「SSH 连接目标」混淆——SSH 连的是跳板机,数据库在另一台机器上 - 如果跳板机防火墙严格,确保它允许从自身发往目标数据库的出向连接(
10.10.20.5:5432),不是只放行你的本机 IP
连接池配置不合理,查三条数据就触发超时或连接泄漏
GUI 客户端默认不显式管理连接池,但一旦开多个 SQL 标签页、反复执行查询、又没关结果集,max connections 很快被耗尽。PostgreSQL 默认 max_connections = 100,而 DBeaver 默认每个连接会独占一个后端进程,且不自动回收空闲连接。
实操建议:
- DBeaver:进连接设置 →
Connection settings→Driver properties,加参数tcpKeepAlive=true和socketTimeout=30(单位秒),避免僵死连接堆积 - DataGrip:Preferences → Database → Connection Pool → 把
Maximum pool size改成5~10,勾选Remove abandoned connections,并设Idle timeout为60秒 - TablePlus 没暴露池参数,靠手动控制:执行完语句立刻点
Close Result,禁用「Auto commit」防止隐式长事务,关闭不用的标签页 - 所有工具里,避免用
SELECT *查大表——结果集未取完前连接不会释放,哪怕你点了停止按钮
SSL 模式设成 require 却没配证书,连接直接拒绝而非降级
生产库通常强制 SSL,但 GUI 工具默认 SSL 模式是 prefer 或 disable。设成 require 后若服务端没提供有效证书链,或客户端没信任 CA,连接会立刻报错 FATAL: no pg_hba.conf entry for host 或 SSL connection has been closed unexpectedly,而不是退回到非 SSL。
实操建议:
- 先确认数据库侧 SSL 状态:
SHOW ssl;和SELECT * FROM pg_stat_ssl; - DBeaver / DataGrip 的 JDBC URL 末尾加
&sslmode=require&sslrootcert=/path/to/ca.crt;ca.crt必须是 PEM 格式、且包含完整信任链 - TablePlus 在连接高级设置里打开
Use SSL,类型选Require,再上传Root Certificate文件——不能只传 client cert - 若用自签名证书,别信「忽略证书验证」选项:DBeaver 的
sslmode=allow实际不生效,DataGrip 的「Trust server certificate」仅对 Java 信任库生效,最好把 CA 导入系统或 JVM 信任库
连接复用与并发执行导致事务状态混乱
多个 SQL 标签页共享同一连接(尤其 TablePlus 默认行为),或者在同一个连接里并发跑多条语句,极易触发 current transaction is aborted, commands ignored until end of transaction block。这不是网络问题,是 PostgreSQL 的事务原子性保护机制在起作用。
实操建议:
- 关闭 DBeaver / DataGrip 的「Open separate connection for each editor tab」——看起来省资源,实际让事务上下文完全不可控
- TablePlus 默认每个查询新建连接,但「Run all queries」时仍可能复用;执行前务必检查右下角显示的
Connection ID是否一致,不一致就说明有隐式切换 - 任何涉及
BEGIN/COMMIT的脚本,必须单标签页、单连接、手动控制执行顺序;别依赖「自动提交」开关,它只影响 DML,不影响 DDL - 生产环境排查时,优先查
pg_stat_activity,看state是idle in transaction还是active,再结合backend_start和xact_start判断是否卡在事务里
真正麻烦的从来不是连上,而是连上之后你不知道当前连接背后挂了多少个没结束的事务、有没有被别的标签页偷偷改了 search_path、或者 SSL 握手失败后连接对象还残留在池里占着坑。这些状态看不见,但每一条都可能让下一次查询突然变慢或失败。










