PostgreSQL Authentication Methods Compared: SCRAM, MD5, TLS, and Client Certificates
A practical comparison of PostgreSQL authentication methods for production apps, including SCRAM, legacy MD5, TLS verification, client certificates, and role design.
Choosing a PostgreSQL authentication method is easy to postpone until something breaks: a leaked password, a driver that cannot connect through TLS, or an audit that asks how database users are verified. The right answer is not always the strongest-sounding mechanism. It depends on who connects, where the connection comes from, what the client library supports, and how much certificate or secret lifecycle work the team can actually maintain.
For most managed PostgreSQL applications, the practical baseline is simple: use encrypted transport, prefer SCRAM password authentication over legacy MD5, keep credentials out of source control, and use narrower database roles than the application technically could use. Client certificates can add useful identity proof for controlled infrastructure, but they also add issuance, rotation, and debugging work. This guide compares the common choices so you can pick a setup that is secure enough without making deployments fragile.
What PostgreSQL is authenticating
PostgreSQL authentication has two layers that are often discussed together but configured separately. The server first decides which authentication rule applies to a connection. That rule is normally expressed in pg_hba.conf, where entries match connection type, database, user, and client address. Then the selected method decides how the client proves identity: a password exchange, a client certificate, a local operating-system identity, or another supported method.
Transport security is related but not identical. TLS protects the connection from being read or modified in transit and can also verify the server name when clients use strict modes such as verify-full. Authentication proves who is connecting to PostgreSQL. A production setup usually needs both: encrypted transport so credentials and data are protected on the network, and a strong authentication method so the server is not accepting the wrong client.
PostgreSQL authentication methods compared
The table below focuses on application and service-to-database connections, not every method PostgreSQL supports. Local peer authentication and operating-system integrated methods can be excellent for server administration, but SaaS applications usually connect over TCP from application runtimes, workers, jobs, and migration tools.
| Method | Best fit | Strength | Main tradeoff |
|---|---|---|---|
scram-sha-256 password auth | General production application access | Modern challenge-response password authentication and safer password storage than legacy MD5 | Still depends on secret handling, role scope, and rotation discipline |
md5 password auth | Legacy clients and old deployments | Broad compatibility with older tooling | PostgreSQL documentation treats SCRAM as the stronger option; MD5 should not be the new default |
| TLS with server verification | Any remote production connection | Protects traffic and helps the client verify the database endpoint | Requires correct CA and hostname configuration in drivers |
| Client certificate authentication | Controlled infrastructure, service identity, high-assurance access | Proves possession of a private key and can be tied to certificate identity | Certificate issuance, storage, rotation, and incident response become operational responsibilities |
| Broad shared application user | Small prototypes only | Simple to start | Hard to audit, rotate, or limit when multiple services share one credential |
The safest default for a typical web application is not a single magic setting. It is SCRAM authentication over TLS, with one database role per application boundary and a clear rotation path. If you also need client certificates, add them deliberately rather than using them as a substitute for basic role hygiene.
SCRAM should be the default password choice
PostgreSQL supports several password authentication methods, including scram-sha-256, md5, and clear-text password. For new production systems, SCRAM is the better default. The PostgreSQL documentation describes SCRAM-SHA-256 as a challenge-response scheme and notes that it is more secure than MD5. It also avoids sending the password itself over the wire during authentication.
There are two practical checks before standardizing on SCRAM. First, make sure application drivers and migration tools support it. Modern drivers generally do, but old language runtimes, old JDBC drivers, or forgotten admin scripts can be the real blocker. Second, check how passwords are stored. PostgreSQL uses the password_encryption setting when a password is set or changed. If a role still has an older password verifier, changing the pg_hba.conf method alone may not complete the migration.
A careful migration usually starts by inventorying clients, updating drivers, rotating application passwords so they are stored with SCRAM, and then tightening the host-based authentication rule. Do this in staging first. Authentication changes fail closed, which is good for security but unforgiving during a deploy.
MD5 is compatibility, not a strategy
MD5 authentication remains visible because many older PostgreSQL installations used it for years and many examples on the internet still mention it. That does not make it the right new default. If you are creating a new managed PostgreSQL deployment today, MD5 should be treated as a compatibility bridge for clients that cannot yet use SCRAM.
The important operational point is to avoid half-migrations. If one service uses SCRAM, another still uses MD5, and several scripts share the same database role, the team has made rotation harder than it needs to be. Split roles by application boundary, upgrade the clients that still require legacy behavior, and retire MD5 rules when they no longer serve a specific compatibility need.
TLS verifies the path, not just the password
Password authentication answers one question: does the client know the secret for this PostgreSQL role? TLS answers a different question: is this connection protected, and is the client talking to the database endpoint it expects? For remote production connections, TLS should not be an afterthought.
The strictest common libpq mode is verify-full, which verifies the server certificate chain and checks that the host name matches. Some application stacks use different option names, but the goal is the same: avoid accepting any encrypted endpoint just because it presented a certificate. In managed environments, this usually means using the platform-provided connection details and CA guidance rather than inventing per-service TLS settings.
A common failure mode is relaxing TLS to fix a deployment quickly and never returning to the issue. If a driver cannot validate the CA or hostname, document why, fix the certificate path or host configuration, and then move back toward verification. ArmorDB users should start from the connection details in the dashboard and keep environment-specific values in deployment secrets; the connection documentation is the right internal starting point.
When client certificates are worth it
Client certificate authentication can be valuable when you control the runtime environment and want PostgreSQL to verify that a connecting service possesses a private key, not just a password. PostgreSQL can use certificate authentication directly, and pg_hba.conf also supports client certificate verification options for host SSL entries. This is useful for tightly managed production networks, privileged jobs, or service boundaries where password-only access is not enough.
The tradeoff is operational. Certificates have lifetimes, private keys need secure storage, and rotation needs a runbook. If a certificate expires on a quiet Sunday, the database may be healthy while the application cannot connect. If a private key leaks, the response is different from rotating a password because the team must revoke or replace certificate trust as well as update deployments.
Use certificates when the organization can maintain them. Do not add them to a small app simply to feel more secure while the same app still uses an overprivileged shared role and untested restore process. Security controls are strongest when the supporting operations are boring.
A practical setup for SaaS teams
A small SaaS stack usually has at least three database access paths: the web application, background workers, and migrations or admin scripts. Giving all three the same superuser-style role is convenient, but it removes useful blast-radius boundaries. A better pattern is to create a normal application role for runtime queries, a more privileged migration role for schema changes, and narrowly scoped read-only roles for analytics or support workflows.
Keep secrets in your deployment platform, not in source control or local .env files that get copied around without review. Rotate credentials when people leave the team, when a CI system changes, or when a secret might have appeared in logs. For production-facing apps, pair authentication with connection pooling so password rotation and reconnect storms do not create a second incident. The PgBouncer guide is a useful companion when many services or serverless workers connect to the same database.
| Application boundary | Recommended access pattern | Why it helps |
|---|---|---|
| Web app runtime | SCRAM-authenticated role with only required privileges | Limits damage from app-level credential exposure |
| Background workers | Separate role when jobs touch broader data or run long transactions | Makes rotation and incident diagnosis cleaner |
| Migration tool | Privileged role used only during deploys | Keeps DDL rights out of normal request handling |
| Analytics or support | Read-only role or carefully scoped views | Reduces accidental writes and improves auditability |
| Emergency admin | Human-controlled path with strong review | Keeps break-glass access separate from app secrets |
This is not bureaucracy. It is the difference between rotating one exposed worker credential and rotating every production database secret during an incident.
Migration checklist
If your current setup is legacy password authentication, move in small steps. Inventory every client that connects to the database, including one-off scripts and CI jobs. Upgrade drivers that cannot use SCRAM. Rotate passwords so PostgreSQL stores modern verifiers. Test strict TLS settings from the same runtime that production uses. Then update host-based authentication rules and watch connection errors during a staged rollout.
Do not combine authentication changes with a large schema migration or application release. A small connection failure is easy to understand when it is the only change. The same failure is much harder to debug when it appears alongside new code, new pool sizes, and new migrations.
Takeaway
For most teams, the right PostgreSQL authentication posture is SCRAM over verified TLS, scoped roles, and disciplined secret rotation. MD5 belongs on a retirement plan, not in new designs. Client certificates are powerful when the team can operate them well, but they are not a substitute for narrow privileges or clean connection management. Start with the boring secure default, then add stronger identity controls only where the workload and operations justify them.
Sources and further reading
- PostgreSQL documentation: password authentication, SCRAM, MD5, and
password_encryption: https://www.postgresql.org/docs/current/auth-password.html - PostgreSQL documentation:
pg_hba.confauthentication records and client certificate options: https://www.postgresql.org/docs/current/auth-pg-hba-conf.html - PostgreSQL documentation: SSL support and libpq
sslmodebehavior: https://www.postgresql.org/docs/current/libpq-ssl.html - PostgreSQL documentation: certificate authentication: https://www.postgresql.org/docs/current/auth-cert.html
Topic
Data-Specs
Updated
Jun 20, 2026
Read time
8 min read
ArmorDB Engineering writes about PostgreSQL operations, security, and infrastructure decisions for teams building production apps on ArmorDB.
Read next
Tech-News & Trends · 7 min read
PostgreSQL 18 Temporal Constraints: What WITHOUT OVERLAPS and PERIOD Change
PostgreSQL 18 adds temporal primary keys, unique constraints, and foreign keys. Here is what changed, when to use them, and what to test before production.
Read articleShort-Form & Quick Fixes · 5 min read
How to Fix PostgreSQL Lock Timeout Errors Safely
A practical quick fix for PostgreSQL lock timeout errors: how to find blockers, recover safely, tune timeouts, and prevent repeat incidents.
Read article