PostgreSQL Connection String Builder

PostgreSQL Connection String Builder

Build a correct postgresql:// URI and the equivalent keyword/value string — with the user and password properly percent-encoded, not just concatenated.

Connection

TLS & extras

URI form

Keyword/value form

How to use this tool

  1. Fill in user, password, host, port and database name. Password is optional here only because it is common to inject it separately from a secrets manager at deploy time.
  2. Pick an sslmode. require is the sane minimum for anything not on localhost; verify-full is the only mode that actually stops a man-in-the-middle.
  3. Add any extra driver parameters as KEY=VALUE lines — connect_timeout, application_name, and pooler-specific flags are common.
  4. Use the URI form for ORMs, connection poolers and anything that reads a single DATABASE_URL-style string. Use the keyword/value form for psql, pg_dump, and libpq-based tools that accept it directly.
  5. If your password contains : / ? # @ or a space, check the note under the output — the URI form needs those percent-encoded, and this tool does it correctly rather than leaving a string that silently connects to the wrong place, or not at all.

PostgreSQL accepts connection parameters in two genuinely different formats, and most tooling only speaks one of them. The URI form, postgresql://user:password@host:port/dbname?param=value, follows RFC 3986 and is what ORMs, connection poolers like PgBouncer, and anything expecting a single DATABASE_URL environment variable wants. The keyword/value form, host=... port=... dbname=... user=..., is libpq’s native format and is what psql, pg_dump, and most C-based tooling accept as a single string with no URI parsing involved.

The critical difference is what “special” means in each format. In a URI, the characters : / ? # @ % are structural — they are how the parser finds the boundary between user and password, between host and path, between path and query string. A password containing a literal @ will, if not encoded, be parsed as the separator between userinfo and host, silently pointing the connection at the wrong host entirely, or producing an error that looks nothing like “your password has an at-sign in it.” Percent-encoding replaces each reserved byte with % plus its two-digit hex value, so p@ss becomes p%40ss and the parser sees one unambiguous password again.

The keyword/value format has no such structural characters at all — it is not a URI, so : / ? # @ mean nothing special there and pass through as plain bytes. What that format does care about is whitespace: a value containing a space must be wrapped in single quotes, and a single quote or backslash inside the value must itself be backslash-escaped, or the parser will read the string as ending early. These are two unrelated escaping problems that happen to apply to the same password, which is exactly why generating both forms by hand is error-prone enough that people reach for a tool like this one.

sslmode is a sliding scale, not an on/off switch, and the names are easy to misread. disable and allow permit or barely-prefer an unencrypted connection. prefer (the historical default) tries TLS but silently falls back to plaintext if the server does not offer it — which means a misconfigured server downgrades you without any warning. require forces encryption but does not check the certificate at all, so it still allows a machine-in-the-middle with a self-signed cert. Only verify-ca and verify-full validate the server certificate against a trusted CA, and only verify-full also checks the hostname matches — that is the mode you want for anything crossing a network you do not fully control.

The database name itself can also contain characters that need encoding in the URI path segment — a forward slash or a percent sign in a database name is unusual but valid, and this tool encodes it the same way it encodes the password, rather than assuming database names are always simple identifiers.

Frequently asked questions

Why do I need to percent-encode my password?

Because the URI form treats : / ? # @ as structural delimiters, not literal characters. An unencoded @ in your password gets read as the boundary between the password and the host, which silently breaks the connection or points it somewhere unintended. Percent-encoding replaces each reserved character with its %XX hex escape so the parser sees one unambiguous field.

What is the actual difference between sslmode=require and verify-full?

require only guarantees the traffic is encrypted — it does not check that the certificate is trustworthy, so a machine-in-the-middle presenting any certificate, even a self-signed one, is accepted. verify-full checks the certificate against a trusted CA and confirms the hostname matches. Use verify-full whenever the connection crosses a network you do not fully control.

Why doesn’t the keyword/value form need percent-encoding?

Because it is not a URI — it is libpq’s own key=value syntax, where : / ? # @ have no special meaning at all. That format only needs escaping for whitespace, single quotes and backslashes inside a value, which is a completely different set of rules from URI encoding.

Which form should I put in an environment variable?

The URI form, almost always — it is what DATABASE_URL conventionally holds and what most ORMs, connection poolers and 12-factor-style app configs expect as one string. Reach for the keyword/value form specifically for psql, pg_dump, or other libpq command-line tools.

What does sslmode=prefer actually do?

It attempts an encrypted connection first, but silently falls back to an unencrypted one if the server does not support TLS — there is no error, no warning, just a plaintext connection. It is the historical libpq default, not a safe one; use require or stricter for anything beyond a local database.