PostgreSQL provides strong authentication and role management features out of the box, but by default, it does not enforce password reuse rules or automatically track repeated authentication failures. This gap becomes critical in production systems where database credentials are shared across applications, automation scripts, and teams.
The credcheck extension fills this gap by adding password history enforcement and authentication failure tracking directly inside PostgreSQL.
In this blog, we will explore:
- What credcheck is and why it matters
- How the extension works internally
- How to build and install it from source
- How to configure PostgreSQL correctly
- Examples of all major functions
- Use cases
This guide is written for DBAs, backend engineers, and anyone interested in PostgreSQL internals and security extensions.
What is the Credcheck Extension?
Credcheck is a PostgreSQL C extension developed by HexaCluster that enhances database security by enforcing:
- Password history tracking – Prevents users from reusing old passwords
- Authentication failure tracking – Detects repeated login failures and bans roles
Unlike application-level controls, credcheck works inside PostgreSQL itself, making it effective for all clients (psql, apps, cron jobs, ORMs, etc.).
GitHub repository:
https://github.com/HexaCluster/credcheck
Why CredCheck is important
By default, PostgreSQL:
- Allows password reuse
- Does not store password change history
- Does not track authentication failure counts
This can lead to:
- Weak password hygiene
- Brute-force login attempts
- Compliance issues
Credcheck addresses these problems without external tooling.
Extension Architecture Overview
Credcheck consists of:
- C code (credcheck.c)
- Hooks into PostgreSQL authentication and password change logic
- SQL files (credcheck--X.Y.Z.sql)
- Define types, views, and SQL-level functions
- Event trigger support
- Tracks role changes and password updates
Because it hooks into authentication, the extension must be loaded at server startup.
Building and Installing credcheck from Source
You downloaded version 4.3 and built it against PostgreSQL 18.
Directory Structure
credcheck-4.3/
+-- credcheck.c
+-- credcheck.control
+-- credcheck--4.3.0.sql
+-- updates/
+-- event_trigger.sql
+-- Makefile
Download the source code of the credcheck extension
git clone https://github.com/HexaCluster/credcheck.git
Compile the Extension
make USE_PGXS=1 PG_CONFIG=/usr/lib/postgresql/18/bin/pg_config
Install the Extension
sudo make USE_PGXS=1 PG_CONFIG=/usr/lib/postgresql/18/bin/pg_config install
This installs:
- credcheck.so> PostgreSQL library directory
- SQL and control files> extension directory
Creating the Extension
Connect to PostgreSQL:
psql -p 5433
Create the extension:
CREATE EXTENSION credcheck;
Verify installation:
\dx+ credcheck
You should see:
- Functions
- Custom types
- Views
Example:
postgres=# \dx+ credcheck
Objects in extension "credcheck"
Object description
-----------------------------------------------------------------------
function pg_banned_role()
function pg_banned_role_reset()
function pg_banned_role_reset(name)
function pg_password_history()
function pg_password_history_reset()
function pg_password_history_reset(name)
function pg_password_history_timestamp(name,timestamp with time zone)
type pg_banned_role
type pg_banned_role[]
type pg_password_history
type pg_password_history[]
view pg_banned_role
view pg_password_history
(13 rows)
Required Configuration: shared_preload_libraries
If you try to use the functions immediately, you will see errors like:
ERROR: credcheck must be loaded via shared_preload_libraries
This is expected.
Edit postgresql.conf:
You can view the path of postgres.conf file like this
postgres=# show config_file ;
config_file
-----------------------------------------
/etc/postgresql/18/main/postgresql.conf
(1 row)
Go to the parameter named shared_preload_libraries
shared_preload_libraries = 'credcheck'
Restart PostgreSQL:
sudo systemctl restart postgresql
This step is mandatory because credcheck hooks into authentication.
Objects Created by credcheck
After successful loading:
Views
- pg_banned_role
- pg_password_history
Functions
- pg_banned_role()
- pg_banned_role_reset()
- pg_banned_role_reset(name)
- pg_password_history()
- pg_password_history_reset()
- pg_password_history_reset(name)
- pg_password_history_timestamp(name, timestamptz)
Practical Examples: Using CredCheck in Real Life
This section demonstrates simple and effective examples to understand how the credcheck extension works in daily PostgreSQL administration.
1. Authentication Failure Tracking (Login Ban)
Purpose:
You want PostgreSQL to automatically block users after repeated failed login attempts.
Step 1: Enable Authentication Failure Limit
ALTER SYSTEM SET credcheck.max_auth_failure = 2;
SELECT pg_reload_conf();
Meaning
A user will be banned after 2 failed login attempts.
Step 2: Trigger Login Failures
psql -U postgres -p 5433
Enter a wrong password twice.
Step 3: User Gets Banned
On the next attempt, PostgreSQL blocks the user:
FATAL: rejecting connection, user "postgres" has been banned
Example:
postgres@cybrosys:/home/cybrosys$ psql -p 5433 -U postgres
Password for user postgres:
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: FATAL: password authentication failed for user "postgres"
postgres@cybrosys:/home/cybrosys$ psql -p 5433 -U postgres
Password for user postgres:
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: FATAL: rejecting connection, user 'postgres' has been banned
Step 4: Check Banned Users
SELECT * FROM pg_banned_role;
Shows:
- Which user is banned
- Failure count
- Ban timestamp
This is useful for security audits and monitoring.
Example:
postgres=# select * from pg_banned_role ;
roleid | failure_count | banned_date
-------------+---------------+----------------------------
postgres | 2 | 2026-01-01 17:39:29.518929
(1 row)
Step 5: Unban a Specific User
SELECT pg_banned_role_reset('postgres');Step 6: Unban All Users
SELECT pg_banned_role_reset();
Best Use Case
- Emergency access recovery
- Incident response handling
2. Adding Delay to Failed Logins (Anti-Brute Force)
Purpose:
You want to slow down brute-force attacks.
Enable Authentication Delay
ALTER SYSTEM SET credcheck.auth_delay_ms = 3000;
SELECT pg_reload_conf();
Every failed login attempt pauses for 3 seconds before returning an error.
This makes automated attacks extremely slow.
3. Password Strength Enforcement (Basic Example)
Purpose:
You want strong passwords with:
- Minimum length
- At least one digit
- At least one special character
Configure Password Rules
ALTER SYSTEM SET credcheck.password_min_length = 8;
ALTER SYSTEM SET credcheck.password_min_digit = 1;
ALTER SYSTEM SET credcheck.password_min_special = 1;
SELECT pg_reload_conf();
Weak Password (Rejected)
CREATE USER weak_user PASSWORD 'password';
Result:
postgres=# CREATE USER weak_user PASSWORD 'password';
ERROR: password does not contain the configured credcheck.password_min_digit characters (1)
Strong Password (Accepted)
CREATE USER strong_user PASSWORD 'Pass@1234';
User created successfully.
4. Preventing Password Reuse
Purpose:
Users should not reuse their last 2 passwords.
Enable Password Reuse Policy
ALTER SYSTEM SET credcheck.password_reuse_history = 2;
SELECT pg_reload_conf();
Password Change History
CREATE USER reuse_user PASSWORD 'Abc@1234';
ALTER USER reuse_user PASSWORD 'Xyz@5678';
Reusing Old Password (Blocked)
ALTER USER reuse_user PASSWORD 'Abc@1234';
postgres=# ALTER USER reuse_user PASSWORD 'Abc@1234';
ERROR: Cannot use this credential following the password reuse policy
View Password History
SELECT rolename, password_date
FROM pg_password_history
WHERE rolename = 'reuse_user';
Result:
rolename | password_date
------------+----------------------------------
reuse_user | 2026-01-01 23:17:30.996003+05:30
reuse_user | 2026-01-01 23:17:31.003545+05:30
(2 rows)
Purpose
- Auditing password changes
- Compliance verification
5. Reset Password History (Admin Action)
Reset for One User
SELECT pg_password_history_reset('reuse_user');Reset for All Users
SELECT pg_password_history_reset();
Useful When
- Migrating environments
- Security policy reset
- Emergency recovery
6. Excluding Users from Policies (Whitelist)
Purpose:
Application users should not be blocked.
Add to Whitelist
ALTER SYSTEM SET credcheck.whitelist = 'app_user,service_user';
SELECT pg_reload_conf();
Effect
- Password rules ignored
- Login ban disabled
7. Monitoring with Functions
Get Banned Users (Programmatically)
SELECT pg_banned_role();
Example:
pg_banned_role
----------------------------------------
(16388,3,"2026-01-01 17:45:26.916198")
(1 row)
Get Password History Summary
SELECT pg_password_history();
Example:
pg_password_history
------------------------------------------------------------------------------------------------------------------------
(first_login_user,"2026-01-01 23:20:55.764843+05:30",4c47cbbcb95715601d98fad489c033c7ef7b6b96afea81b74e876b00143a0117)
(expiry_user,"2026-01-01 23:20:04.908903+05:30",f3f0f383bfdf049e0826dd4f43c8863828711aea11b3a9602ca4d15ab61f52be)
(2 rows)
These functions are ideal for:
- Cron jobs
- Monitoring dashboards
- Security alerts
Conclusion
Using credcheck, PostgreSQL can now:
- Block brute-force login attempts
- Enforce strong password policies
- Prevent password reuse
- Force password expiration
- Require password change on first login
- Centralize credential security inside the database
All without modifying application code.
Database credential security is often treated as an application concern, but relying only on application-level checks leaves gaps that attackers can exploit. PostgreSQL intentionally keeps authentication rules simple, which makes it flexible but also shifts responsibility to administrators. The credcheck extension addresses this gap by bringing strong, configurable credential policies directly into the database layer.
By using credcheck, PostgreSQL can enforce password complexity, prevent password reuse, control password lifetime, and block users after repeated authentication failures. These protections apply uniformly to all connection methods, ensuring consistent behavior regardless of how users or applications connect. Features such as authentication delays, password history tracking, and forced password changes significantly reduce the risk of brute-force attacks and weak credential practices.
For production systems where security, compliance, and operational reliability matter, credcheck provides a practical and effective enhancement to PostgreSQL’s native capabilities. When combined with proper role management and network-level controls, it helps establish a strong foundation for database security without requiring changes to application code.