{
  "id": 7935903,
  "title": "Why ExitOnForwardFailure=yes does not prove your database is reachable",
  "url": "https://urgent.news/2026/09/17/why-exitonforwardfailure-yes-does-not-prove-your-database-is-reachable",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-17T03:12:31.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/nexusshell/why-exitonforwardfailureyes-does-not-prove-your-database-is-reachable-4o22"
  },
  "original_language": "en",
  "account": "An SSH tunnel can be running on your laptop while the service on the remote end is not reachable. The ExitOnForwardFailure=yes setting in SSH does not automatically check if the destination database is reachable. This is important to remember when a PostgreSQL client reports a connection failure, even though the SSH tunnel is still active.\n\nTo demonstrate this, a small test was conducted on September 17, 2026, using a loopback-only setup with macOS, OpenSSH 10.3p1, Node.js 25.6.1, and ssh2 1.17.0. The test used the system OpenSSH client, an in-process SSH server, and a minimal HTTP target. The SSH client had local forwarding enabled with the ExitOnForwardFailure=yes option.\n\nDuring the test, the SSH server tried to connect to a closed loopback port, which the operating system responded with ECONNREFUSED. Despite this, the local TCP connection to the forwarding port succeeded, and the SSH process remained running. When the HTTP target was started, a new request through the existing tunnel returned the expected result.\n\nStarting a second SSH process with the same local listening port resulted in an \"Address already in use\" error, causing the second process to exit with code 255. This test shows that the failure to connect to the destination is a separate issue from the SSH tunnel's forwarding listener.\n\nFor a database reachable through an SSH gateway, you can test the connection with a command like: ssh -N -T -o ExitOnForwardFailure=yes -L 127.0.0.1:15432:db.internal:5432 developer@gateway.example. Replace the example names with your actual connection details, verify the host key, and keep the process running. The database client should connect to 127.0.0.1 on port 15432, while the SSH connection on the gateway resolves to db.internal on port 5432.\n\nThe test reveals that the layer failing should be investigated, such as SSH authentication, key selection, and server authentication policies. Check for an address already in use on the Mac, choose a different unused local port, and update the database client accordingly. If the forwarding destination is set to the loopback address on the Mac, that connection originates in the SSH server's network context, not your local machine.\n\nAfter the local TCP connection succeeds, a failure in the forwarding channel may indicate issues with the destination hostname, port, service listener, routing, or forwarding policy on the SSH side. The PostgreSQL server may report an authentication error, and you should inspect the database identity and authentication rules. TLS certificate verification failures should also be investigated, as the connection reached the PostgreSQL server.\n\nDisabling verification to make the error disappear is not recommended, as it would not verify the database identity or authentication. Use your normal database client with the appropriate credentials and TLS settings for the final check. SSH authentication and database authentication are separate processes, and database TLS may still be required even if the SSH encryption ends at the gateway.",
  "summary": "An SSH tunnel can be listening on your laptop while the service behind it is unavailable. ExitOnForwardFailure=yes is useful, but it does not turn the SSH process into a database health check. This distinction matters when a PostgreSQL client says “connection failed” even though ssh -N is still running. Before changing credentials, separate the local listener, the SSH transport, the destination…",
  "key_points": [
    "SSH tunnel active doesn't guarantee database reachability",
    "ExitOnForwardFailure=yes doesn't check database connection",
    "Separate issues: SSH tunnel vs destination database reachability"
  ],
  "editors_take": "The ExitOnForwardFailure setting in SSH only ensures the local forwarding listener is active, not that the destination database is reachable, requiring separate investigation of potential connection issues.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}