SSH隧道连不上PostgreSQL最常见的原因是本地端口被占用或远程PostgreSQL未监听127.0.0.1;需确保pg_hba.conf允许127.0.0.1/32连接并重载配置,同时用ssh -v验证隧道建立、添加ServerAlive参数防断连。
SSH隧道连不上PostgreSQL:端口转发没生效
最常见的情况是本地端口被占用,或者远程 postgresql 没监听 127.0.0.1(只监听 localhost 或 unix socket)。ssh 的 -l 参数要求目标服务必须能被跳板机的 127.0.0.1 访问到,不是“能 ping 通”就行。
- 确认跳板机上能连上 PostgreSQL:
psql -h 127.0.0.1 -U user -d db,失败就先调通这步 - 检查 PostgreSQL 配置:
listen_addresses必须包含'127.0.0.1'(不能只写'localhost',某些系统解析不一致) - 启动隧道时加
-v查看日志:ssh -L 5433:127.0.0.1:5432 user@jump-host -v,留意是否出现channel 1: open failed: connect failed - 避免本地端口冲突:别默认用
5432,改用5433或其他空闲端口
pgAdmin / psql 连接报错:FATAL: no pg_hba.conf entry
错误本质是 PostgreSQL 拒绝了来自 127.0.0.1 的连接请求,不是 SSH 问题。跳板机上的 pg_hba.conf 必须显式允许 127.0.0.1/32 的连接方式,且认证方法要匹配。
- 在跳板机的
pg_hba.conf中添加一行:host all all 127.0.0.1/32 md5(或trust仅限测试) - 改完后必须重载配置:
pg_ctl reload或sudo systemctl reload postgresql,restart不必要且有风险 - 注意顺序:
pg_hba.conf是从上到下匹配,更宽松的规则(如0.0.0.0/0)如果写在前面,可能掩盖真实问题 - 不要用
hostssl行——SSH 隧道本身不触发 SSL 握手,这条规则不会命中
连接成功但查询慢、超时:TCP 缓冲区和 Keepalive 缺失
SSH 隧道本质是长连接,网络波动或中间设备(NAT 网关、防火墙)静默断连时,PostgreSQL 客户端不会立刻感知,表现为卡顿或 server closed the connection unexpectedly。
- 在 SSH 命令中加入保活参数:
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -L 5433:127.0.0.1:5432 user@jump-host - PostgreSQL 客户端侧可设
tcp_keepalives_idle(例如 psql 加-c "set tcp_keepalives_idle=60"),但不如 SSH 层控制可靠 - 避免在笔记本休眠/切换网络后继续复用旧隧道——手动中断再重建比依赖自动重连更稳
- 大结果集导出时,别让隧道承载太久:用
pg_dump加--host=127.0.0.1 --port=5433,而非直连远程地址
跳板机账号权限过大:最小权限原则怎么落地
很多人用跳板机的 root 或 PostgreSQL 超级用户建隧道,其实完全没必要。只要该系统账号能执行 ssh 并访问 PostgreSQL 的本地 socket 或端口即可。
- 创建专用跳板账号:
adduser --disabled-password --gecos "" pg-tunnel,不给 shell(设为/usr/sbin/nologin) - 用
sudo限制命令:在/etc/sudoers加pg-tunnel ALL=(postgres) NOPASSWD: /usr/bin/psql,但隧道本身不需要这个 - 真正关键的是 PostgreSQL 的
pg_hba.conf只允该用户从127.0.0.1登录,且角色权限按需授予(比如只读角色) - 别在客户端保存跳板机密码——用
ssh-keygen生成密钥对,ssh-copy-id推送公钥,禁用密码登录
隧道本身不加密应用层数据(PostgreSQL 协议明文),所以 sslmode=require 在隧道里意义不大;但如果你顺手开了,记得服务端也配好证书,否则会因 SSL 握手失败静默断连。










