PostgreSQL Connection String Errors: Diagnose the URL

Ghazi · August 4, 2026

A PostgreSQL connection URL compresses the user, password, host, port, database, and options into one line. That convenience also makes one unescaped character or copied pooler port look like an unrelated network or password failure.

Split the URL into fields, redact the password, and verify the scheme, encoded credentials, hostname, port, database path, and query parameters separately. Test the same values with psql, then rebuild the URL instead of editing a secret-filled string by eye.

Compare URI and keyword-value formats

postgresql://app_user:p%40ss%3Aword@db.example.com:5432/app?sslmode=require

host=db.example.com port=5432 dbname=app \
user=app_user password='p@ss:word' sslmode=require

The URI password is percent-encoded. Keyword-value strings use their own quoting rules and should not be pasted where a URI is required.

Check the shape before the credentials

libpq accepts postgresql:// and postgres:// URIs. The database name follows the host and port as the path. Connection options follow ? and use & between parameters.

A missing slash, doubled @, fragment marker, or copied quotation mark can change how the entire URL is parsed. Do not post the original URL in an issue or chat. Replace the password and any private host before sharing it.

Use the documented URI structure

postgresql://[user[:password]@][host][:port][/dbname][?name=value&...]

Percent-encode URI credentials

Characters such as @, :, /, ?, #, %, and spaces have structural meaning in a URI. Percent-encode them when they are data inside a user name, password, database name, or parameter value.

Encode the individual value once, not the complete URL. Encoding the separators would destroy the structure. Encoding an already encoded percent sign produces a different password.

  • @ becomes %40
  • : becomes %3A
  • / becomes %2F
  • ? becomes %3F
  • # becomes %23
  • % becomes %25
  • space becomes %20

Treat IPv6 and Unix sockets explicitly

Wrap a literal IPv6 address in square brackets in a PostgreSQL URI. A hostless connection can select a Unix-domain socket, which is different from TCP through localhost. When comparing two clients, state the host rather than assuming both chose the same transport.

Valid IPv6 and Unix-socket examples

postgresql://app_user@[2001:db8::1234]:5432/app

postgresql:///app?host=/tmp

Verify provider pooler details

Managed providers can issue direct and pooled URLs with different hostnames, user formats, ports, and session behavior. A Supabase transaction pooler commonly differs from its session pooler. A Neon pooled hostname contains a pooler marker. Copy the intended connection type as a complete unit.

An error after swapping only the port may not mean the port is closed. The pooler may expect another host or user string. Return to the provider's connection panel and compare every field.

Map errors to the failing layer

Connection refused points to the listener and port. Timeout points to reachability. Host not found points to DNS or a malformed host. Password authentication failed means the server responded but rejected authentication. Database does not exist means the path or dbname is wrong. Certificate errors belong to SSL trust or hostname verification.

Use the local PostgreSQL connection string builder to parse and rebuild a URL in the browser. For TLS parameters, read the sslmode guide. For a refused local connection, start with the Mac listener checklist.

Test without leaking the password

Prefer an interactive prompt or a protected password file over placing credentials directly in shell history. Set a short connect_timeout while troubleshooting unreachable hosts, especially when a URL lists several hosts.

Test the reconstructed fields

psql "host=db.example.com port=5432 dbname=app \
user=app_user sslmode=require connect_timeout=5"

psql prompts for a password when the server requests one and no password source supplies it.