A PostgreSQL password reset can look complete while the role still receives a legacy verifier if the cluster default writes the wrong hash type. Setting password_encryption to scram-sha-256 before resetting roles makes newly stored database passwords use SCRAM-SHA-256 instead of legacy MD5 hashes.
PostgreSQL chooses the stored password format when CREATE ROLE, ALTER ROLE, or the psql \password command sets a password. The setting does not rewrite existing rows in pg_authid, so the useful proof is both the active password_encryption value and a reset role whose stored verifier starts with SCRAM-SHA-256.
Client authentication rules still control which password method a connection must use. A pg_hba.conf rule set to scram-sha-256 requires a SCRAM-stored password and clients that support SCRAM, while legacy md5 rules can still accept SCRAM-stored passwords during a staged migration. Keep a working local superuser path until affected roles have been reset and remote logins have been tested.
Related: How to configure pg_hba.conf in PostgreSQL
Related: How to secure a PostgreSQL server
$ sudo -u postgres psql -Atc "SHOW server_version;" 18.4 (Ubuntu 18.4-0ubuntu0.26.04.1)
SCRAM-SHA-256 password encryption and authentication are available in PostgreSQL 10 and later.
$ sudo -u postgres psql -Atc "SHOW password_encryption;" scram-sha-256
$ sudo -u postgres psql -P pager=off -c "SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules WHERE auth_method IN ('md5','scram-sha-256','password') ORDER BY line_number;"
line_number | type | database | user_name | address | auth_method
-------------+------+---------------+-----------+-----------+---------------
125 | host | {all} | {all} | 127.0.0.1 | scram-sha-256
127 | host | {all} | {all} | ::1 | scram-sha-256
131 | host | {replication} | {all} | 127.0.0.1 | scram-sha-256
132 | host | {replication} | {all} | ::1 | scram-sha-256
(4 rows)
Do not switch a rule to scram-sha-256 while it still covers roles whose passwords are stored as MD5 hashes. Reset those role passwords first or keep a compatible rule during the migration.
$ sudo -u postgres psql -c "ALTER SYSTEM SET password_encryption = 'scram-sha-256';" ALTER SYSTEM
ALTER SYSTEM writes the override to postgresql.auto.conf. If configuration management owns postgresql.conf directly, make the same setting there instead of leaving two competing sources.
$ sudo -u postgres psql -c "SELECT pg_reload_conf();" pg_reload_conf ---------------- t (1 row)
$ sudo -u postgres psql -Atc "SELECT setting, source FROM pg_settings WHERE name='password_encryption';" scram-sha-256|configuration file
$ sudo -u postgres psql postgres=# \password appuser Enter new password for user "appuser": Enter it again: postgres=# \q
A password passed directly in a shell command can leak through shell history, process inspection, terminal logs, or ticket transcripts. Use \password or another approved secret-handling path for real credentials.
$ sudo -u postgres psql -Atc "SELECT rolname, rolpassword LIKE 'SCRAM-SHA-256$%' FROM pg_authid WHERE rolname='appuser';" appuser|t
pg_authid is readable only by superusers. Keep raw password hashes out of tickets, screenshots, and shared transcripts.
$ sudo -u postgres psql -Atc "SHOW hba_file;" /etc/postgresql/18/main/pg_hba.conf
$ sudoedit /etc/postgresql/18/main/pg_hba.conf
host appdb appuser 192.0.2.0/24 scram-sha-256
Incorrect pg_hba.conf ordering can lock out remote clients. Keep local shell or console access available until the test login succeeds.
$ sudo -u postgres psql -c "SELECT pg_reload_conf();" pg_reload_conf ---------------- t (1 row)
$ psql -h 127.0.0.1 -U appuser -d postgres -c "\conninfo"
Password for user appuser:
Connection Information
Parameter | Value
----------------------+------------------------
Database | postgres
Client User | appuser
Host | 127.0.0.1
Server Port | 5432
Protocol Version | 3.0
Password Used | true
SSL Connection | true
SSL Protocol | TLSv1.3
SSL Cipher | TLS_AES_256_GCM_SHA384
(11 rows)