PG19 Hacktober: 31 Days of New Features: PostgreSQL Authentication Updates: Password Warnings, Expiration & RADIUS Changes

PostgreSQL 19 makes three authentication changes: a password-expiration warning, a warning after successful MD5 authentication, and removal of native RADIUS support. Together they improve password management, flag legacy methods, and drop the insecure RADIUS/UDP implementation.

In this post, we verify that the password-expiration warning and the MD5 authentication warning work correctly and reliably. It covers warning behavior, message delivery to clients, configuration options, and compatibility with existing authentication workflows. It also presents some thoughts of the developers w.r.t dropping the native RADIUS support.

1. Password Expiration Warning
The server warns users when their password is close to expiring, so they can change it in time. The backend sends the message, but the client application must display it.

2. Warning Upon Successful MD5 Authentication
A warning now appears when a login succeeds with an MD5 password. It helps administrators find users and applications still on MD5 and move them to SCRAM-SHA-256 gradually.

3. Time to Drop RADIUS Support?
Native RADIUS is removed because of the security problems with RADIUS over UDP, including BlastRADIUS, and the cost of maintaining it. Users who still need RADIUS can use PAM-based RADIUS instead.

Feature 1: Password Expiration Warning

The Problem

When a PostgreSQL role has a VALID UNTIL date set, users get zero advance notice before their password expires. They only find out when login suddenly fails:

FATAL:  password authentication failed for user "foo"

The real cause: password expiration is buried in the server log:

DETAIL:  User "foo" has an expired password.

This is especially painful for application service accounts that break silently at 2 AM.

The Solution: password_expiration_warning_threshold

A new server-side GUC was introduced that emits a WARNING at login when a password is within a configurable time of expiring.

$ psql -h localhost -U test -d postgres
Password for user test:
WARNING: password will expire soon
DETAIL: The password for role "test" will expire in 3 days.
psql (19devel)

The warning appears for all clients, not just psql and is also written to the server logs for audit purposes.

Configuration
# postgresql.conf
password_expiration_warning_threshold = 7d # default; 0 = disabled
SettingMeaning
7d (default)Warn 7 days before expiry
24hWarn 24 hours before expiry
0Disable warnings entirely
INT_MAXNo upper limit — set to whatever suits your policy

The GUC is PGC_SIGHUP, so no restart is required to change it.

What the Warning Looks Like

The message uses the largest meaningful time unit, with proper singular/plural forms:

DETAIL:  The password for role "alice" will expire in 3 days.
DETAIL: The password for role "bob" will expire in 2 hours.
DETAIL: The password for role "carol" will expire in 15 minutes.
DETAIL: The password for role "dave" will expire in less than 1 minute.

Key Design Decisions

The patch went through 17 versions before being committed. Here’s how the major design questions were resolved:

Server-side or client-side?

Original idea: A psql-only variable \set PASSWORD_EXPIRE_WARNING 7.

Problems:

(1) Not everyone uses psql.

(2) psql can’t reliably tell which auth method was actually used.

Decision: Server-side — all clients benefit automatically.

Show days, hours, or an exact timestamp?

OptionExampleVerdict
Days onlyexpires in 3 day(s)“(s)” anti-pattern; poor plurals
Days + Hoursexpires in 2 days and 7 hoursComplex; multi-plural problem
Largest unit onlyexpires in 3 days / expires in 2 hoursChosen
Exact timestampexpires at 2026-02-05 16:56Requires mental math; timezone confusion

GUC name debate

CandidateProblem
password_expire_warningToo terse
password_warning_thresholdAmbiguous — warning about what?
password_expiration_warning_threshold Chosen — descriptive and unambiguous

Default on or off?

Off-by-default is pretty much guaranteed to not help most people. — Tom Lane
Decision: Default ON at 7 days. Set to 0 to disable.

Implementation Highlights

  • Warnings emit at the end of InitPostgres() — after the connection is fully established — so no information is leaked if an error occurs mid-setup.
  • Works for all backend types that authenticate with a password, including logical replication connections.
  • VALID UNTIL 'infinity' is silently skipped — no false warnings.
  • A new connection warnings infrastructure on Port was introduced, reusable by future warnings (see Feature 2 below).

NOTE

Long-lived connections are not yet covered. A user who connects with >7 days remaining won’t receive a mid-session reminder. The goaway patch (a separate ongoing effort) may address periodic in-session notifications in the future.

Feature 2: Warning on MD5 Password Authentication

The Problem

MD5 password hashing has been considered cryptographically weak for years. PostgreSQL already supports scram-sha-256 as the modern replacement, but many users and applications are still unknowingly using MD5. There is currently no feedback to alert users or administrators that MD5 is in use.

The Solution: A WARNING at MD5 Login

Building directly on the connection warnings infrastructure introduced in Feature 1, a new warning is emitted whenever a role successfully authenticates using an MD5-hashed password:

$ psql -h localhost -U legacy_user -d mydb
Password for user legacy_user:
WARNING: authentication with MD5-hashed passwords is deprecated
DETAIL: The role "legacy_user" authenticated using an MD5-hashed password. Consider migrating to scram-sha-256.psql (19devel)

The warning also appears in server logs, giving DBAs visibility into which accounts still need migration.

Why This Matters

MD5 is broken for password hashing for several reasons:

IssueDetail
Collision attacksMD5 is cryptographically broken
No salting per-loginMakes offline dictionary attacks easier
No iterationFast to crack with modern hardware
Protocol leakageMD5 auth sends a hash that can be replayed

scram-sha-256 Addresses all of these: salted, iterated, and challenge-response based (no hash is sent over the wire).

How to Migrate Away from MD5

Step 1 — Find all MD5 accounts:

SELECT rolname FROM pg_authid WHERE rolpassword LIKE 'md5%';

Step 2 — Require SCRAM in postgresql.conf:

password_encryption = scram-sha-256

Step 3 — Have each user reset their password:

ALTER ROLE legacy_user PASSWORD 'new_secure_password';

Step 4 — Enforce SCRAM in pg_hba.conf:

host all all 0.0.0.0/0 scram-sha-256

WARNING

Changing password_encryption does not automatically re-hash existing passwords. Each role must reset their password for the new hash type to take effect.

Relationship to Feature 1

This feature deliberately reuses the same connection warnings infrastructure introduced for password expiration warnings. Nathan Bossart designed it as a generic list of (message, detail) pairs stored on Port, making it easy to stack multiple warnings:

WARNING:  password will expire soon
DETAIL: The password for role "old_user" will expire in 2 days.
WARNING: authentication with MD5-hashed passwords is deprecated
DETAIL: The role "old_user" authenticated using an MD5-hashed password.

This composable design means future connection-time warnings can be added cleanly without touching the core plumbing again.

Feature 3: Drop native RADIUS Support

What Is Being Proposed?

Rather than invest in a RADIUS/TLS client for a hypothetical user, the proposal is:

ActionScope
Add a deprecation notice in the documentationPostgreSQL 14–18 (back-branches)
Remove native RADIUS client code entirelyPostgreSQL 19 (HEAD)
Clean up Windows select() and non-thread-safe UDP hacksPostgreSQL 19 (HEAD)
Community Consensus
ContributorView
Tom LaneRemove from HEAD; preserve back-branches until zero-user status confirmed
Jacob Champion+1 to removal; add a back-branch WARNING as a kindness to users
Álvaro HerreraAdd WARNING to gauge real-world usage before full removal
Aleksander Alekseev+1, perfectly reasonable
Thomas MunroProposed the removal; created wiki migration guide

Three patches were submitted:

  • 0001 — Mark RADIUS deprecated in docs
  • 0002 — Drop RADIUS authentication support (34 KB of code removed)
  • 0003 — Remove obsolete Windows select() and UDP infrastructure

The Migration Path: RADIUS via PAM

You can already do RADIUS better using PAM with the module maintained by the FreeRADIUS project. Here’s a complete setup:

/etc/pam.d/postgresql

#%PAM-1.0auth    required    pam_radius.so require_message_authenticatoraccount required    pam_permit.so

/etc/radius.conf — point PAM at your RADIUS server

# Server[:port]    SharedSecret    Timeout    Retries
127.0.0.1 shared_secret 3 3

pg_hba.conf — tell PostgreSQL to use PAM

host all all 127.0.0.1/32 pam pamservice=postgresql
Why PAM Is Better
ConcernNative RADIUSPAM + pam_radius
Maintained byPostgreSQL teamFreeRADIUS project
Supports RADIUS/TLS No Yes (via config)
BlastRADIUS safeOnly with mitigation patch Yes (require_message_authenticator)
Does it require fixing within Postgres?Yes No

Security Impact and Recommendations

These changes encourage administrators to adopt stronger authentication practices and identify configurations that require attention.

  • Password expiration: Configure an appropriate warning period and ensure that client applications display server notices to users.
  • MD5 authentication: Identify roles and applications using legacy password authentication and plan a migration to SCRAM-SHA-256. Verify client compatibility before changing authentication settings.
  • RADIUS authentication: Review existing pg_hba.conf configurations before upgrading. If RADIUS is required, evaluate PAM-based authentication or another supported approach for the operating system and deployment.

Administrators should test these changes in a development or staging environment before applying them to production systems.

Conclusion:

PostgreSQL 19 takes steps toward stronger authentication security by improving password-expiration awareness, warning about successful MD5 authentication, and removing native RADIUS support that relied on the insecure RADIUS/UDP variant.

Together, these changes help administrators identify outdated authentication configurations and plan migrations to more secure alternatives. Careful testing is essential to confirm warning behavior, client compatibility, configuration handling, and the reliability of authentication workflows. By validating these changes before deployment, teams can improve their security posture while minimizing disruption to existing applications.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top