DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

SSH 隧道已建立,连接 MySQL 时仍报 channel open failed: Connection refused

SSH 认证和本地监听成功后,目标数据库连接仍可能失败。针对同机 MySQL 仅监听 IPv4 回环的情况,修正 -L 的远端目标,不扩大数据库公网监听。

SSH 已显示认证成功,本地转发端口也开始监听,但数据库客户端一连接,终端就出现:

channel 2: open failed: connect failed: Connection refused

如果 MySQL 和 SSH 服务在同一台主机、同一网络命名空间中,而 MySQL 只监听 127.0.0.1:3306,把本地转发的目标写成该服务器的公网 IP 就不对应这个监听地址。SSH 能登录,不代表服务器公网地址的数据库端口也能接受连接。

这里针对 OpenSSH 的 -L 本地转发。数据库在另一台主机或另一个容器网络命名空间时,不能直接照用服务器的 127.0.0.1,应先确定 SSH 服务端实际能访问的数据库端点。

日志中的成功分别发生在哪一层

Authentication succeeded 或 Authenticated to 说明 SSH 身份验证通过。Local forwarding listening 说明客户端建好了本地监听。之后的 direct-tcpip 通道才处理一次真正的目标连接。

OpenSSH 收到本地端口上的连接后,才从 SSH 服务端连接 -L 中指定的目标主机和端口。目标连接被拒绝,可以发生在前两步已经成功之后。

ExitOnForwardFailure=yes 可以让转发监听建立失败时退出,但不负责让后续每一次目标连接都成功。不要为了消掉错误去掉这个选项,也不要看到 SSH 进程仍在就判定数据库已连通。

单凭 Connection refused 还不能确认只有一种原因。目标服务未运行、监听了其他地址或端口、网络设备主动拒绝,都可能给出相近现象。下面的修复以“数据库确实只在同机 IPv4 回环监听”为前提。

在 SSH 服务器上确认监听地址

登录实际承接 SSH 连接的 Linux 主机后查看 TCP 3306:

ss -lnt 'sport = :3306'

关注本地地址列。127.0.0.1:3306 表示 IPv4 回环监听,与服务器公网 IP 上的 3306 不是同一端点。还应结合现有 MySQL 服务配置或管理工具确认这确实是目标实例,不要仅按端口号猜进程。

没有监听时,应先处理数据库服务状态;只有 ::1:3306 时,也不能把 IPv4 回环示例当成已经匹配。若数据库在容器内,容器的 127.0.0.1 属于容器自身,宿主机上的检查和转发不能直接访问它。

确认同机 127.0.0.1:3306 正常监听后,无需为了 SSH 隧道把数据库改成监听 0.0.0.0,也不需要开放公网 3306。修正 SSH 转发的目标地址即可保留原来的数据库暴露范围。

本地监听与远端目标都明确写出

在自己的客户端电脑启动测试隧道,账号和域名换成已授权的 SSH 入口:

ssh -N -v -S none -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:13306:127.0.0.1:3306 \
  -l tunneluser dbhost.example.com

第一段 127.0.0.1:13306 是客户端电脑的监听地址;第二段 127.0.0.1:3306 由 SSH 服务端连接,指向服务器上的数据库。两处地址相同,所属主机不同。

示例保持前台运行,不加 -f,便于观察一次数据库连接触发的日志;-S none 避免复用已有控制连接。13306 是示例空闲端口,如果已被占用,换一个本地端口并同步修改数据库客户端配置,不要结束不明进程来腾位置。

在另一个本地终端,用自己的数据库账号连接隧道入口:

mysql --protocol=TCP -h 127.0.0.1 -P 13306 -u app_user -p

-p 后不直接写密码,按提示输入。这里显式选择 TCP,避免 Unix 平台 mysql 客户端把 localhost 解释为本地 socket 连接。数据库账号与 SSH 账号是两套身份,不能把 SSH 用户名直接当成 MySQL 授权账号。

如果使用带内置 SSH 隧道的图形客户端,SSH 主机填写登录入口,数据库主机则填写从 SSH 服务端视角可达的地址。在本篇同机回环条件下,它应是 127.0.0.1。不要同时套用内置隧道和手工隧道却仍填写另一套端口;选择一种方式并核对各字段所属主机。

从连接拒绝走到数据库验证

使用修正后的目标再发起数据库连接,SSH 不应再针对这次请求出现同样的目标连接拒绝。随后仍需核对数据库身份认证、连接到的实例和实际业务权限。若变成 Access denied,说明应继续检查数据库授权,不能通过允许所有来源或关闭认证解决。

如果改成回环地址后仍被拒绝,重新核对 SSH 入口是否为预期主机、数据库实际监听端点和网络命名空间。不要因为“同一个域名”就假定 SSH 与数据库进程一定处于同一个系统环境。

保存原连接配置后再调整;测试结束先退出数据库客户端,再在这次前台 SSH 终端按 Ctrl-C 结束隧道。停止隧道会断开经它建立的连接,因此不要对正在承载业务的隧道直接执行这个测试收尾操作。需要回退时恢复之前保存的客户端连接配置,清除这次临时入口;整个修复无需改变 MySQL 数据目录或服务器公网监听。