InletDownload

Connect · Railway

Connect to Railway Postgres from your Mac

Railway databases are private by default. Either add Public Access in the service’s Networking settings and use DATABASE_PUBLIC_URL, or run railway connect postgres --tunnel-only and connect to the local tunnel.

Updated 9 October 2026

What you need

  • A PostgreSQL service in your Railway project (added from the + New button or the ⌘K menu on the project canvas).
  • One way in from your Mac:
    • Public Access, which gives the database a TCP proxy address on the internet, or
    • the Railway CLI, which can open an SSH tunnel to a database that has no public address.

Find your connection details

The PostgreSQL service exposes its details as variables: PGHOST, PGPORT, PGUSER, PGPASSWORD, PGDATABASE and DATABASE_URL. Those point at Railway’s private network, so they only work from other services in the project.

Public Access. Railway deploys databases private by default. To reach one from your Mac, open the service’s Settings → Networking and add Public Access. Railway creates a TCP proxy, a generated host and port such as shuttle.proxy.rlwy.net:15140, and fills in a DATABASE_PUBLIC_URL variable with the external connection string. Railway bills network egress through the TCP proxy.

Tunnel instead. If you’d rather not expose the database, the CLI can tunnel to it over SSH:

railway connect postgres --tunnel-only

It prints the host, port, user, password, database and full connection URL for the local end of the tunnel, and keeps the tunnel open until you press Ctrl-C. Railway suggests this for pointing a GUI client at the database. Without --tunnel-only, railway connect opens psql directly.

Connection string

DATABASE_PUBLIC_URL has the usual form, with the proxy’s host and port:

postgresql://<user>:<password>@<proxy-host>.proxy.rlwy.net:<proxy-port>/<database>

The port is the one Railway generated, not 5432. If you point your own domain at the proxy with a CNAME, keep Railway’s port. See PostgreSQL connection strings.

TLS

Railway runs its own SSL-enabled PostgreSQL image, because the official Docker image doesn’t turn TLS on. According to that image’s repository, it creates its own certificate authority and server certificate when the database is first set up (and replaces them on a restart or redeploy when they’re within 30 days of expiry). The certificate names localhost and the service’s private host name, not the public proxy host.

So sslmode=require works and encrypts the connection, but verify-ca and verify-full can’t succeed against the certificates macOS trusts. The TCP proxy forwards raw TCP, so the TLS session runs between your client and the database itself.

Connect with Inlet

  1. Copy DATABASE_PUBLIC_URL from the service’s variables and paste it into Inlet; Inlet fills in the connection form. If you used railway connect postgres --tunnel-only, paste the URL it printed instead, and leave the tunnel running while you work. You can also choose New Connection and type the fields.
  2. Under TLS, choose require.
  3. Save the password in the Keychain, or have Inlet ask for it each time.
  4. Tag the environment. A production connection opens read-only, so the server refuses writes until you unlock it for ten minutes.

Connect from the command line

The CLI finds the right variables and starts psql for you (it needs psql installed):

railway connect postgres

For another environment, add --environment staging. Or use the public URL directly:

psql "postgresql://<user>@<proxy-host>.proxy.rlwy.net:<proxy-port>/<database>?sslmode=require"

Homebrew’s libpq package includes psql (keg-only: /opt/homebrew/opt/libpq/bin/psql).

Troubleshooting

  • Connection refused or a timeout with the DATABASE_URL host: that’s the private address. Use DATABASE_PUBLIC_URL, or the tunnel.
  • Wrong port: the TCP proxy has its own port; 5432 won’t work on the proxy host.
  • verify-full fails: expected, because the certificate comes from the database’s own authority and doesn’t name the proxy host. Use require.
  • password authentication failed: copy the password again from the variables, and percent-encode special characters in a URL; see special characters in passwords.
  • The tunnel closed: --tunnel-only holds it open only while the command runs.

Related

Sources