Postgres Connection Strings Explained: Format, Examples, and Common Errors
What every part of a PostgreSQL connection string (DATABASE_URL) means, how to write one, special characters in passwords, sslmode options, pooled vs direct connections (including Supabase's ports), and how to fix the errors people hit most.
Most apps connect to Postgres with a single line in an environment variable, usually called DATABASE_URL:
postgresql://app_user:s3cret@db.example.com:5432/myapp?sslmode=require
That's a connection string (or connection URI). It packs everything your app needs to find and log in to the database into one URL. Here's what each piece means and how to fix it when it doesn't work.
The parts
postgresql:// app_user : s3cret @ db.example.com : 5432 / myapp ? sslmode=require
scheme user password host port database options
| Part | Meaning |
|---|---|
postgresql:// |
The scheme. postgres:// also works with most tools. |
app_user |
The database user (role) to log in as. |
s3cret |
That user's password. |
db.example.com |
The server's hostname or IP address. localhost for a database on the same machine. |
5432 |
The port. 5432 is Postgres's default and can be omitted. (Ports explained.) |
myapp |
The database name on that server. |
?sslmode=require |
Options, like a URL query string. |
(It follows the same structure as a web address — see anatomy of a URL.)
Special characters in the password
If the password contains characters that mean something in a URL — @, :, /, ?, #, % — they must be percent-encoded, or the string is parsed wrongly:
| Character | Encoded |
|---|---|
@ |
%40 |
: |
%3A |
/ |
%2F |
# |
%23 |
? |
%3F |
% |
%25 |
So a password of p@ss#1 becomes p%40ss%231. Symptoms of getting this wrong: errors mentioning an unexpected host, or "password authentication failed" even though the password is right. The simplest fix for new databases: generate passwords with only letters and numbers (and make them long).
sslmode: encryption to the database
sslmode controls whether the connection is encrypted:
| Value | Meaning |
|---|---|
disable |
No encryption. Only for a database on the same machine or a private network. |
prefer |
Use encryption if the server offers it (a common default). |
require |
Always encrypt; don't verify the server's certificate. |
verify-full |
Encrypt and verify the certificate and hostname — the most secure. |
For a database reached over the internet, use at least require, ideally verify-full. Many hosted providers require SSL and will refuse unencrypted connections.
Pooled vs direct connections
Many hosts give you two connection strings:
- a direct connection to Postgres, and
- a pooled connection through a connection pooler (like PgBouncer), often on a different port.
Supabase, for example, uses port 5432 for direct and session-mode pooled connections and 6543 for its transaction-mode pooler. Use the pooled string for apps that open many short-lived connections (especially serverless functions), and the direct one for running migrations and admin tasks — some migration tools don't work through a transaction-mode pooler. See Postgres connection pooling.
Keep it secret
A connection string contains a password with access to all your data. Treat it like any secret:
- keep it in an environment variable, never in code (environment variables explained),
- never put it in frontend code or a
VITE_/NEXT_PUBLIC_variable, - make sure
.envis in.gitignore, - use a database user with only the permissions your app needs.
Common errors and what they mean
| Error | Usual cause |
|---|---|
password authentication failed for user |
Wrong password, wrong user, or an unencoded special character |
connection refused / ECONNREFUSED |
Nothing listening at that host and port — wrong host/port, database not running, or a firewall |
ENOTFOUND / could not translate host name |
Hostname typo, or a hostname that only works inside a private network (like a Docker service name used from your laptop) |
database "myapp" does not exist |
Wrong database name, or it hasn't been created yet |
no pg_hba.conf entry for host / SSL required |
The server requires SSL — add sslmode=require |
too many connections / remaining connection slots are reserved |
Too many open connections — use the pooled string or reduce your pool size |
self-signed certificate / certificate verify failed |
Using verify-full without the provider's CA certificate — supply it, or use require |
A classic one: the app works locally but not in production because DATABASE_URL still says localhost. On the server, localhost means the server itself. See why does my app work locally but not in production?
Testing a connection string
With psql installed:
psql "postgresql://app_user:s3cret@db.example.com:5432/myapp?sslmode=require"
If you get a myapp=> prompt, the string works, and the problem is in how your app reads it. Type \q to quit. More ways to look inside: how to view your Postgres database.
The summary
- A connection string is
postgresql://user:password@host:port/database?options. - Percent-encode special characters in passwords.
- Use
sslmode=requireorverify-fullover the internet. - Use pooled strings for the app, direct ones for migrations.
- Keep it in a server-side environment variable.
EasySpawn provisions PostgreSQL on every server and hands your app its connection details as DATABASE_URL automatically — no copying passwords between dashboards. See how it works or join the waitlist.
Related: What Is a Database? · Postgres vs MySQL · Docker Compose for Local Development · What Is an ORM? · ECONNREFUSED 127.0.0.1:5432
Keep reading
Dates and Time Zones in Apps: How Not to Get Them Wrong
Reminders sent an hour late, bookings on the wrong day, 'yesterday' that's actually today. Why dates are hard, the golden rule (store UTC, display local), ISO 8601, time zones vs offsets, daylight saving traps, and how to check your AI-built app handles them.
What Is MongoDB? A Beginner's Guide to Document Databases
MongoDB stores data as flexible JSON-like documents instead of tables. How it works, what collections and documents are, where it shines, where Postgres is the better pick, and why AI tools sometimes reach for it.