Every app that stores anything — a to-do list, a bank balance, your signup email — reaches its database through a single line of text. It sits in a .env file, an environment variable, or a hosting dashboard, and it looks like this:
postgresql://app_user:********@db.prod.internal:5432/analytics?sslmode=requireThat string is the entire contract between your application and its database. Read it wrong, and you get connection refused, silent plaintext traffic, or a password pasted into a public screenshot. This post walks through each piece, where Postgres and MySQL differ, and the mistakes that show up in real incidents — the recent Railway breach being the sharpest reminder that these strings are the keys to everything.

Anatomy of a connection string: each colored part of a postgresql:// URL, labeled.
The seven parts of a connection URL
A connection URL has the same shape as any web URL, which is why the password part trips people up:
- Scheme — postgresql:// for Postgres (postgres:// also works) or mysql:// for MySQL and MariaDB. The scheme tells the driver which protocol to speak.
- Username — who you are. Percent-encoded, so a space becomes %20.
- Password — separated by a colon. Also percent-encoded: @ becomes %40, / becomes %2F. This is the single most common failure — an unencoded @ makes everything after it look like a hostname.
- Host — where the database lives. localhost for same-machine setups, a domain or IP everywhere else.
- Port — 5432 for Postgres, 3306 for MySQL. Can be omitted to use the default.
- Database name — the path. Postgres connects to a specific database; MySQL to a schema.
- Query parameters — options like sslmode=require or connect_timeout=10.
A password like p@ss/w0rd cannot go into a URL as typed: the @ ends the password field and the / looks like the start of a path. Both characters have to be percent-encoded first.p@ss/w0rd only survives the trip inside the URL once both special characters are encoded:
p@ss/w0rd raw breaks parsing
p%40ss%2Fw0rd encoded connects fineThe same information can also be written as key-value pairs — that is what a JDBC URL is, and what GUI clients often show you:
jdbc:postgresql://db.prod.internal:5432/analytics?user=app_user&password=********sslmode: the part that decides whether you are encrypted
A connection string without an SSL mode is not neutral. Postgres defaults to prefer, and MySQL to PREFERRED — both of which happily fall back to an unencrypted connection if the server allows it. The modes, weakest to strongest:
- disable / DISABLED — plaintext, fine only on localhost or a private network.
- prefer / PREFERRED — encrypt if possible, but accept plaintext.
- require / REQUIRED — refuse to connect unencrypted, but do not check the server's certificate.
- verify-ca / VERIFY_CA — also checks the server certificate comes from a trusted authority.
- verify-full / VERIFY_IDENTITY — additionally checks the certificate hostname matches.
Over the public internet, verify-full or VERIFY_IDENTITY is what you want. The tool on BrowserStay always writes the chosen mode into the URL, so the string cannot silently fall back to prefer.
Where connection strings go wrong
Real incidents keep teaching the same three lessons:
- They are secrets living in plain text. A connection URL contains a working password. It belongs in an environment file that is gitignored, never in code, screenshots, or support tickets. In October 2026, an attacker's access to customer environment variables on Railway forced a platform-wide credential rotation — the connection strings themselves were the loot.
- Changing the string does not retire the old secret. Editing a password in your .env updates your app, but the old password usually stays valid at the issuing provider until you revoke it there. Rotation means revoke-and-reissue at the source, then update the string.
- Encoding bugs masquerade as auth failures. A password with a slash or an @ in it will break parsing before the server ever sees it. If a connection fails with "password authentication failed" but the same password works in psql or the mysql client, check the encoding first.
From string to running connection
Once the URL is correct, wiring it up is one line in most stacks. In Node's pg, the connection string goes straight into the pool:
// Node.js — pg
import pg from "pg";
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });In Python, psycopg 3 takes the same URL as its conninfo argument:
# Python — psycopg 3
import os, psycopg
with psycopg.connect(os.environ["DATABASE_URL"]) as conn:
conn.execute("select 1")In Go, pgx.Connect accepts it unchanged:
// Go — pgx
conn, err := pgx.Connect(ctx, os.Getenv("DATABASE_URL"))Our Database URL Builder generates the URL and shows a minimal working snippet for each of those stacks, filled in with your values — built entirely in your browser, since the string contains a password.




No comments yet