37.6 pg_hba.conf: Authentication Methods and Order of Rules
Right, let’s talk about the pg_hba.conf file, the bouncer at the door of your PostgreSQL club. This file, pg_hba.conf (Host-Based Authentication), is where you decide who gets in, how they prove their identity, and which doors they’re allowed to knock on. It’s a simple concept that, through the magic of enterprise IT, often becomes a tangled mess of panic and misconfiguration. I’m here to make sure that doesn’t happen to you.
The first thing you need to internalize is that PostgreSQL reads this file from top to bottom and uses the first matching rule. Not the best match. The first one. This is the most common way people accidentally lock themselves out of their own database. You put a super restrictive rule at the top for 10.0.0.5/32 and a nice, open 0.0.0.0/0 rule right below it, and you’ll wonder why that one host can’t connect. The answer is it matched the restrictive rule first and never got to the permissive one. Order is absolutely everything.
The Anatomy of a Rule
Each line in pg_hba.conf is a rule with seven potential fields. Let’s break one down:
# TYPE DATABASE USER ADDRESS METHOD [OPTIONS]
host sales_db sales_app 10.0.1.0/24 md5
- Type:
hostmeans a TCP/IP connection (SSL or non-SSL).hostsslmeans only SSL-encrypted connections.hostnosslis its weird, insecure cousin you should probably avoid.localis for local socket connections. - Database: This isn’t the user’s default database; it’s the database they are trying to connect to. You can use
all, a specific name likesales_db, or even a comma-separated list. You can also usesameuserwhich is a nifty trick that allows a user to connect to a database of the same name. - User: Which user is this rule for?
allmeans, well, all users. You can also use a specific username or a group role (prefixed with+). - Address: For
host/hostssltypes, this defines the client’s IP range. It can be a specific IP (192.168.1.100/32), a CIDR mask (192.168.1.0/24), or a hostname (don’t do this, it requires a reverse DNS lookup and will slow everything down). Forlocaltypes, this field should be blank. - Method: This is the fun part—how the user authenticates. This is where the real security decisions are made.
A Tour of Authentication Methods (The Good, The Bad, and The Ugly)
Let’s talk about these methods. Some are heroes, some are deprecated relics, and one (trust) is an open invitation for your data to be stolen.
trust: This is the equivalent of having a sign on your datacenter that says “Free Databases, Just Take One.” If the connection matches the rule, the user gets in. No password. Nothing. Useful for local connections in a secure, single-user environment (like your dev machine), but an absolutely catastrophic idea on any network. Just don’t.reject: The bouncer that immediately says “not tonight, pal.” Useful for explicitly blocking a specific user or network before a more general rule. Great for blacklisting.md5: The old standard. It challenges the client to provide an MD5-hashed version of the password. It’s better than nothing, but MD5 is cryptographically broken. You should be moving past this.`scram-sha-256:** This is the new gold standard. It uses a secure challenge-response mechanism (SCRAM) with SHA-256. It’s immune to replay attacks and is the method you should be using for password-based authentication whenever possible. If you’re starting fresh, use this.
peer:** This is forlocal` connections only. It pulls the client’s operating system username and checks it against the database username. It’s fantastic for scripting and local maintenance on a secure machine, as no password is involved. It just trusts the OS.
Here’s a realistic example for a three-tiered environment:
# TYPE DATABASE USER ADDRESS METHOD
# Block a known bad IP first
host all all 192.0.2.100/32 reject
# Application servers get to connect to a specific app database with strong auth
hostssl app_production app_user 10.0.1.0/24 scram-sha-256
# Developers can access all dbs from the trusted office network, but must use strong auth
hostssl all +dev_roles 203.0.113.0/24 scram-sha-256
# Allow passwordless local connections for the postgres OS user (common for admin)
local all postgres peer
# The "break glass in case of emergency" rule. COMMENT THIS OUT AFTER USE.
# This allows anyone on the local machine to connect as postgres with a password.
# host all postgres 127.0.0.1/32 md5
Best Practices and Gotchas
hostsslis Your Friend: Unless you enjoy packets being snooped on, mandate SSL for any remote connection. Usehostsslinstead ofhost. You’ll need to configure your SSL certificates inpostgresql.conf, but that’s a story for another section.Be Specific, Early: Put your most specific rules (specific IPs, specific users) at the top. Put your general, catch-all rules (like a reject-all) at the very bottom.
The “Oops, I Locked Myself Out” Recovery: If you mess up your
pg_hba.confand can’t connect, don’t panic. Connect via the local socket (which often has apeerortrustrule). On a standard Linux install, this is as easy as becoming thepostgresOS user and runningpsql.sudo su - postgres psqlReload, Don’t Restart: After editing
pg_hba.conf, you don’t need to restart the entire PostgreSQL server. You can just tell it to reload the configuration file. Thepg_reload_conf()function will do this, or you can signal the postmaster from the command line:# Find the pid of the postmaster process and send it a SIGHUP pg_ctl reload -D /path/to/your/data/directory # Or from inside psql: SELECT pg_reload_conf();Test Relentlessly: Your authentication setup is your first line of defense. Test connection attempts from every conceivable user and network location before you assume it’s working. Assume you’ve made a mistake, because you probably have. I always do.