PgDeck

PostgreSQL connection URL

The PostgreSQL connection URL, explained.

One string carries the host, port, database, credentials, and every connection option. It is also where a password containing an @ or a # quietly breaks everything, which is what brings most people here.

Short answer: The format is postgresql://user:password@host:port/database?param=value. postgres:// and postgresql:// are both accepted and identical. Any special character in the username or password must be percent-encoded, because the URL parser splits on those characters before anything else sees them.

PgDeck PostgreSQL desktop client with schema navigation, table filtering, row editing, and SQL tools

Why developers use PgDeck

PgDeck is shaped around PostgreSQL tasks that happen every day: connect, inspect, filter, edit, query, manage structure, copy, and export.

postgres:// and postgresql:// are identical
Special characters in credentials must be percent-encoded
application_name shows up in pg_stat_activity — always set it
options=-c lets you set search_path at connection time
A comma-separated host list gives you client-side failover

Secure connections

Save PostgreSQL connection details with encrypted passwords, SSL settings, URL import, testing, search, edit, and delete actions.

Schema and data grid

Browse schemas and tables, search the table list, pin favorites, filter rows, sort columns, resize columns, and paginate results.

SQL workspace

Run SELECT and non-SELECT statements from multi-tab SQL editors with syntax highlighting and interactive query results.

Staged editing

Edit cells, add rows, duplicate rows, set NULL, stage deletes, review pending changes, and commit everything in one transaction.

How to build a PostgreSQL connection URL

  1. The basic shape

    Scheme, credentials, host, port, database, then query parameters. Both postgres:// and postgresql:// work identically — libpq accepts either, and providers use both, which causes needless confusion. Every part except the scheme can be omitted and will fall back to a default or an environment variable.

    postgresql://alice:s3cret@db.example.com:5432/analytics?sslmode=verify-full
    
    # Equivalent, and equally valid:
    postgres://alice:s3cret@db.example.com:5432/analytics?sslmode=verify-full
  2. Percent-encode special characters

    This is the single most common failure. The parser splits on @, :, /, ?, and # before your password is interpreted, so a password containing any of them produces a wrong host or a cryptic error. Encode them. A password of p@ss/w0rd# becomes p%40ss%2Fw0rd%23.

    # Password: p@ss/w0rd#
    postgresql://alice:p%40ss%2Fw0rd%23@db.example.com:5432/mydb
    
    # @ = %40   : = %3A   / = %2F   ? = %3F   # = %23   space = %20
  3. Add connection parameters

    Anything libpq accepts as a keyword can go in the query string. sslmode is the one that matters most. application_name is worth setting on every connection — it appears in pg_stat_activity, so you can tell which client is running a query when something is stuck.

    postgresql://alice:s3cret@db.example.com:5432/mydb
      ?sslmode=verify-full
      &sslrootcert=/etc/ssl/certs/rds-ca.pem
      &connect_timeout=10
      &application_name=reporting-job
  4. Set a search_path in the URL

    The options parameter passes server settings at connection time, which is how you select a schema without running a SET afterwards. The value needs encoding: -c is fine, but the space before it must become %20.

    postgresql://alice:s3cret@db.example.com/mydb?options=-c%20search_path%3Dsales,public
  5. Unix sockets and omitted parts

    A URL with no host connects over a Unix socket in the default directory — common for local development, where the socket path can also be given explicitly as the host parameter. Omitted credentials fall back to PGUSER and PGPASSWORD or a .pgpass file, which is how you keep passwords out of the URL entirely.

    # Unix socket, default directory
    postgresql:///mydb
    
    # Explicit socket directory
    postgresql:///mydb?host=/var/run/postgresql
    
    # No password in the URL: read from ~/.pgpass
    postgresql://alice@db.example.com/mydb
  6. Multiple hosts for failover

    libpq accepts a comma-separated host list and tries each in turn. With target_session_attrs it will skip hosts that are not accepting writes, which is how a client finds the current primary in a replicated setup without external routing.

    postgresql://alice:s3cret@host1:5432,host2:5432/mydb?target_session_attrs=read-write

Why the encoding trap catches everyone

URL parsing happens before anything understands what a PostgreSQL password is. An @ in the password means the parser sees the text after it as the host, so you get a confusing name-resolution failure rather than an authentication error. Generated passwords frequently contain @, /, and #, which is why this appears the moment a team rotates credentials to something stronger.

Keep credentials out of the URL where you can

A full connection URL in an environment variable ends up in shell history, process listings visible to other users on the machine, crash dumps, and log output. PGPASSWORD or a ~/.pgpass file with 0600 permissions keeps the secret separate from the connection details, and a secret manager is better still. Treat a URL containing a password as a credential, not configuration.

Parameters that are worth setting

sslmode, for the reasons on the SSL page. connect_timeout, so a dead host fails in seconds instead of hanging. application_name, which is the difference between seeing an anonymous idle transaction in pg_stat_activity and knowing exactly which job left it open. The last one costs nothing and repays itself the first time something is stuck.

How providers vary

Supabase offers several strings and they are not interchangeable — pooler and direct behave differently. Neon distinguishes pooled and direct endpoints by a suffix in the hostname. Heroku-style URLs rotate, so hardcoding one guarantees an outage later. Read what the provider hands you rather than assuming a shape, and paste it rather than retyping it.

Pasting beats typing

Every value in a connection URL is exact and most are long: a project reference in a hostname, a username with a dotted suffix, a generated password. Transcribing by hand is where the errors come from. Any decent client imports a URL and fills in the fields, which also means the sslmode comes along rather than being forgotten.

Related PostgreSQL guides

More on choosing, comparing, and running a PostgreSQL desktop client.

What is the PostgreSQL connection URL format?

postgresql://user:password@host:port/database?param=value. The postgres:// scheme is accepted as an identical alias. Every component except the scheme can be omitted and falls back to a default, an environment variable, or a .pgpass entry.

Is postgres:// or postgresql:// correct?

Both. libpq treats them as identical, and different providers use different ones purely by convention. There is no behavioural difference and no reason to convert between them.

How do I use a password with special characters in a connection URL?

Percent-encode them. The URL parser splits on @, :, /, ?, and # before the password is interpreted, so an unencoded @ makes the parser read the wrong hostname. @ becomes %40, / becomes %2F, # becomes %23, and a space becomes %20.

How do I set the schema in a connection URL?

Use the options parameter to pass a server setting at connection time: ?options=-c%20search_path%3Dsales,public. The space after -c must be encoded as %20 and the equals sign as %3D.

Can a connection URL specify more than one host?

Yes. libpq accepts a comma-separated list of host:port pairs and tries each in order. Adding target_session_attrs=read-write makes it skip hosts not accepting writes, which lets a client find the current primary in a replicated cluster.