Secure connections
Save PostgreSQL connection details with encrypted passwords, SSL settings, URL import, testing, search, edit, and delete actions.
PostgreSQL connection URL
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 is shaped around PostgreSQL tasks that happen every day: connect, inspect, filter, edit, query, manage structure, copy, and export.
Save PostgreSQL connection details with encrypted passwords, SSL settings, URL import, testing, search, edit, and delete actions.
Browse schemas and tables, search the table list, pin favorites, filter rows, sort columns, resize columns, and paginate results.
Run SELECT and non-SELECT statements from multi-tab SQL editors with syntax highlighting and interactive query results.
Edit cells, add rows, duplicate rows, set NULL, stage deletes, review pending changes, and commit everything in one transaction.
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-fullThis 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 = %20Anything 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-jobThe 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,publicA 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/mydblibpq 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-writeURL 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.
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.
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.
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.
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.
More on choosing, comparing, and running a PostgreSQL desktop client.
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.
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.
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.
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.
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.