Now-Next

SaaS architecture

no pg_hba.conf entry for host: what it means, measured

PostgreSQL's no pg_hba.conf entry for host, measured on 12 to 18 (not 15): the 'no encryption' tail, Docker's gateway address, hostssl, replication and reload.

Chris van Eijk, Now-Next · · 10 min read

FATAL: no pg_hba.conf entry for host "172.25.0.1", user "postgres", database "postgres", no encryption (SQLSTATE 28000) means the server received your connection, read its client authentication file pg_hba.conf from top to bottom, and found no line for this combination of address, user, database and encryption. It is a refusal before any password is checked, so the password, and even whether the role exists, plays no part. The cause we reproduced most directly is a pg_hba.conf that only allows the loopback addresses, reached from somewhere else: in Docker, the address in the message is then the network gateway, not 127.0.0.1.

We measured on the official postgres Docker images 12.22, 13.23, 14.24, 16.15, 17.11 and 18.6, connecting with psql/libpq 16.15 on the host, and from a second container (the 16.15 one, with its own psql) on the same Docker network, and inside each container with that image’s own psql; pg_basebackup 17.11 ran from the 17 container. All on 27 October 2026. The scripts are linked at the end, so you can repeat most results below.

What does “no encryption” mean in the pg_hba error?

It says how the rejected attempt arrived: without SSL and without GSSAPI encryption. It is not a complaint that encryption is missing, and not a hint that turning SSL on would help. The tail is printed by the server, so it follows the server version, not the client’s: psql 12.22 got no encryption from 18, and psql 18.6 got SSL off from 12. The same psql 16.15 got this from PostgreSQL 12 and 13:

FATAL:  no pg_hba.conf entry for host "172.25.0.1", user "postgres", database "postgres", SSL off

and this from 14, 16, 17 and 18:

FATAL:  no pg_hba.conf entry for host "172.25.0.1", user "postgres", database "postgres", no encryption

With ssl = on and a client that tried SSL, the tail became SSL on on 12 and 13, and SSL encryption on 14 to 18. A fourth variant, GSS encryption, needs a Kerberos setup we did not build. The wording changed in 14: in the server source (src/backend/libpq/auth.c), the 13 branch prints SSL on/SSL off and the 14 branch SSL encryption/no encryption.

The default sslmode=prefer produced two errors in one psql message when the server had SSL on, because libpq tried again without SSL:

psql: error: connection to server at "127.0.0.1", port 55804 failed: FATAL:  no pg_hba.conf entry for host "172.25.0.1", user "postgres", database "postgres", SSL encryption
connection to server at "127.0.0.1", port 55804 failed: FATAL:  no pg_hba.conf entry for host "172.25.0.1", user "postgres", database "postgres", no encryption

Both attempts were refused for the same reason. On 12 and 13 the pair read SSL on, then SSL off. With sslmode=disable there was one line (no encryption, or SSL off on 12 and 13), with sslmode=require one line (SSL encryption, or SSL on).

Why doesn’t the official Docker image give this error for ordinary connections?

Because its pg_hba.conf ends with a line that matches every address:

local   all             all                                     trust
host    all             all             127.0.0.1/32            trust
host    all             all             ::1/128                 trust
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust
host all all all scram-sha-256

That last line was the same in all six images (on 12 and 13 with md5 instead of scram-sha-256). On an untouched 17 container the host connected through the published port without any change. The error appears once the file looks like the one a distribution package ships, which only lets the loopback addresses in over TCP. We installed that file in every container (the local socket lines we kept as trust):

host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256

and every version refused the host, although the host connected to 127.0.0.1. The address in the message is the one the server sees, not the one you typed. Docker forwards the published port, and the connection reaches the server from the gateway of the container’s network: 172.25.0.1 on our network 172.25.0.0/16. From a second container on the same network the message named that container’s own address, 172.25.0.5. Inside the container itself, psql -h 127.0.0.1 did match the loopback line and connected on 14 to 18. (On 12 and 13 it got past pg_hba.conf and then failed with password authentication failed, because those images store the password as md5 and our line said scram-sha-256.) So the same server works from inside the container and refuses your laptop.

Four connections to the same PostgreSQL 17 container, with a loopback-only pg_hba.conf: which address the server saw
  1. psql on the laptop, to 127.0.0.1 and the published portDocker's proxy forwards it, so the server sees the network gateway, 172.25.0.1.
    No line matches: no pg_hba.conf entry
  2. psql in a second container on the same networkThe server sees that container's own address, 172.25.0.5.
    No line matches: no pg_hba.conf entry
  3. psql inside the container, to 127.0.0.1The server sees 127.0.0.1.
    Matches 127.0.0.1/32: connected
  4. psql inside the container, to localhostlocalhost resolved to ::1 first.
    Matches ::1/128; without that line: no pg_hba.conf entry for host "::1"

Measured on 17.11, network 172.25.0.0/16. Your gateway and container addresses come from your own Docker network; look them up with docker network inspect.

We tested two fixes on 17: host all all samenet scram-sha-256 let in the host (via the gateway) and the second container, and an appended range line let in the host. Keep that line as narrow as your network: the gateway itself (172.25.0.1/32 for us) or your Docker network’s subnet from docker network inspect, not all of 172.16.0.0/12, which also holds ordinary LAN and VPN subnets. Keep the published port on 127.0.0.1 as well: in our test every connection through it arrived from the gateway address, so a gateway line admits whatever can reach that port. And do not fix this with trust or POSTGRES_HOST_AUTH_METHOD=trust: behind a published port that lets in everyone who reaches it, without a password. samenet is, in the documentation’s words, “any address in any subnet that the server is directly connected to” — inside our container, that was the Docker network.

Is it the same as Connection refused?

No, and the difference tells you where to look. This error means the server is listening and answered; it is a pg_hba.conf problem. With listen_addresses = 'localhost' the server never sees an outside connection at all. Through the published port psql then got:

psql: error: connection to server at "127.0.0.1", port 55807 failed: server closed the connection unexpectedly
	This probably means the server terminated abnormally
	before or while processing the request.

and from a second container Connection refused. A typo in pg_hba.conf at start-up looks different again: the server did not start, the container exited, and the client got Connection refused on the published port (more on that below). The client-side messages are in Connection refused: is the server running?.

Does a missing user or database cause “no pg_hba.conf entry”?

Not by itself, but the error does not tell you they exist either. A role nosuchrole and a database nosuchdb that did not exist got the same refusal, with those names in it, on every version: the file is checked before the role. Once a line matches, the next error is about the login, as in password authentication failed for user or role does not exist.

The names are matched exactly as the client sends them. With the single line host appdb app 0.0.0.0/0 scram-sha-256 on 17:

user=app dbname=appdb     -- connected
user=app dbname=postgres  -- FATAL:  no pg_hba.conf entry for host "172.25.0.1", user "app", database "postgres", no encryption
user=postgres dbname=appdb -- ... user "postgres", database "appdb", no encryption
user=APP dbname=appdb     -- ... user "APP", database "appdb", no encryption
user=app (no dbname)      -- ... user "app", database "app", no encryption

The last one catches people: without a database name, libpq sent the user name as the database, and the message shows it. A group line host all +tenants … refused app until we ran grant tenants to app, and then let it in without a reload.

Does the order of lines in pg_hba.conf matter?

Yes. The documentation: “The first record with a matching connection type, client address, requested database, and user name is used to perform authentication. There is no ‘fall-through’ or ‘backup’: if one record is chosen and the authentication fails, subsequent records are not considered.” With host all all 172.16.0.0/12 reject above host all all 0.0.0.0/0 scram-sha-256, the host got a differently worded error:

FATAL:  pg_hba.conf rejects connection for host "172.25.0.1", user "postgres", database "postgres", no encryption

With the two lines swapped, it connected. So rejects connection means a line matched and said no, no pg_hba.conf entry means no line matched at all.

Why does hostssl give “no encryption” even with SSL configured?

Because the attempt that was refused came without SSL. We tried each record type against each sslmode on 17, with ssl on and off:

LineServer ssldisableallowprefer (default)require
hostssl all all 0.0.0.0/0 …onno encryptionconnected (SSL)connected (SSL)connected (SSL)
hostnossl all all 0.0.0.0/0 …onconnectedconnectedconnectedSSL encryption
hostssl all all 0.0.0.0/0 …offno encryptionno encryption, twiceno encryptionserver does not support SSL, but SSL was required
hostnossl all all 0.0.0.0/0 …offconnectedconnectedconnectedserver does not support SSL, but SSL was required

A hostssl line on a server with ssl = off can never match. At reload the server logged it, and pg_hba_file_rules showed it, but the file was still loaded:

select line_number, type, address, auth_method, error from pg_hba_file_rules;
--  2 | hostssl | 0.0.0.0 | scram-sha-256 | hostssl record cannot match because SSL is disabled
-- log:  LOG:  F0000: hostssl record cannot match because SSL is disabled
--       HINT:  Set "ssl = on" in postgresql.conf.

The last message in the table, server does not support SSL, but SSL was required, is libpq’s own and never reaches pg_hba.conf.

Why is pg_basebackup refused when psql connects?

Because all in the database column does not cover physical replication. Against the untouched official image, whose last line is host all all all scram-sha-256, pg_basebackup 17.11 from a second container got:

pg_basebackup: error: connection to server at "nnhba-default" (172.25.0.8), port 5432 failed: FATAL:  no pg_hba.conf entry for replication connection from host "172.25.0.6", user "postgres", no encryption

psql with replication=true got the same; with replication=database (a logical replication connection) it connected and ran IDENTIFY_SYSTEM. That matches the documentation: “The value replication specifies that the record matches if a physical replication connection is requested, however, it doesn’t match with logical replication connections.” The image’s own replication lines allow only 127.0.0.1/32 and ::1/128. After appending host replication all all scram-sha-256 and a reload, the same pg_basebackup ran. That was a test container; in production, put the replica’s address in place of the last all.

Do I need to restart after editing pg_hba.conf?

A reload is enough, and it is needed. We appended host all all 172.16.0.0/12 scram-sha-256 on 17: the host stayed refused until select pg_reload_conf();, and connected right after. pg_hba_file_rules already listed the new line before the reload, because, as the documentation says, “this view reports on the current contents of the file, not on what was last loaded by the server”. Use it to check a change before you reload, not to see what is in force.

A typo behaves differently at reload and at start-up. We changed the line to scram-sha256 and reloaded:

select line_number, auth_method, error from pg_hba_file_rules where error is not null;  -- (we also selected type and address)
--  7 |  | invalid authentication method "scram-sha256"
-- log:  LOG:  F0000: invalid authentication method "scram-sha256"
--       CONTEXT:  line 7 of configuration file "/var/lib/postgresql/data/pg_hba.conf"
--       LOG:  00000: /var/lib/postgresql/data/pg_hba.conf was not reloaded

The server kept the rules it had: the host still connected. After a restart of a container with the same typo, the server did not come up:

LOG:  invalid authentication method "scram-sha256"
CONTEXT:  line 129 of configuration file "/var/lib/postgresql/data/pg_hba.conf"
FATAL:  could not load /var/lib/postgresql/data/pg_hba.conf
LOG:  database system is shut down

The container exited with code 1, and the client got Connection refused. So check pg_hba_file_rules for errors before every restart; a reload hides a broken file until the next one.

What if localhost is ::1?

Then a file with only 127.0.0.1/32 refuses it. Inside the container, /etc/hosts maps localhost to both 127.0.0.1 and ::1, and with only the IPv4 line psql 17.11 got:

psql: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  no pg_hba.conf entry for host "::1", user "postgres", database "postgres", no encryption

It reported that one attempt; host=127.0.0.1 connected. The fix is the ::1/128 line that distribution files already have, or connecting to 127.0.0.1.

Which message means what?

What you seeCause we measuredFix
no pg_hba.conf entry for host "172.x.0.1" while connecting to 127.0.0.1loopback-only file, connection through Docker’s published porthost all all <gateway>/32 scram-sha-256, or samenet
no pg_hba.conf entry for host "::1"localhost resolved to IPv6, only 127.0.0.1/32 in the filehost all all ::1/128 scram-sha-256, or connect to 127.0.0.1
… user "app", database "app"no dbname given, libpq used the user namepass the database, or add it to the line
… SSL encryption then … no encryptionsslmode=prefer, both attempts refusedone fix, the cause is not SSL
… no encryption with a hostssl lineclient did not use SSL (disable), or server ssl = offsslmode=require on the client and ssl = on on the server; replacing hostssl with host allows unencrypted logins
… SSL encryption with a hostnossl lineclient required SSLhost instead of hostnossl
pg_hba.conf rejects connection for hosta reject line above the line you addedfind out why the reject line is there; if these clients should get in, put a line for exactly their address above it
no pg_hba.conf entry for replication connectionall does not cover physical replicationhost replication all <range> scram-sha-256
… SSL off / SSL onthe same error from PostgreSQL 12 or 13the same fixes
still refused after editingno reloadselect pg_reload_conf();
server closed the connection unexpectedlylisten_addresses = 'localhost' behind Docker’s portlisten_addresses = '*'

Does the server log say more than the client?

Barely. With log_error_verbosity = verbose the log gave the code, FATAL: 28000: no pg_hba.conf entry for host …, and the source location; psql shows no SQLSTATE for a failed connection, so that is where the 28000 comes from. With log_connections = on it added a line with the client’s port, connection received: host=172.25.0.1 port=38554. There was no DETAIL and no line number: no line matched, so there was none to name. Where this error sits among the others, see our measured SQLSTATE overview.

Reproduce it

Two scripts: setup.sh starts the nine containers (one per version and three extra 17s) on 127.0.0.1 with the test password test, and run.sh installs each pg_hba.conf and prints every client message and log excerpt above. Run PREFIX=pghba BASE=55800 ./setup.sh, then ./run.sh 2>&1 | tee results.txt, and run setup.sh again before every new run.sh, because the run leaves roles and lines behind; it needs psql on the host. The gateway address will be that of your Docker network, not necessarily ours.

What we did not measure

PostgreSQL 15, and GSSAPI encryption (GSS encryption, hostgssenc). Host names in the address column, pg_ident.conf, and clientcert. Whether drivers other than libpq (pgjdbc, node-postgres, asyncpg) show both lines of a prefer retry, or only one. Docker’s default bridge network and rootless or Desktop setups, where the gateway address may differ. Managed services, where the customer often cannot edit pg_hba.conf.

Sources: PostgreSQL 17 documentation on the pg_hba.conf file and the pg_hba_file_rules view, read on 27 October 2026; the message strings in auth.c on the 13 branch and on the 14 branch, read on 27 October 2026. All measurements are our own, on PostgreSQL 12.22, 13.23, 14.24, 16.15, 17.11 and 18.6 in containers, with psql/libpq 16.15 on the host and pg_basebackup 17.11, on 27 October 2026.

Let's talk

What are we building?

One conversation is enough to know whether we fit. Tell us what you have in mind — we will tell you how fast it can happen, and whether we are the right people for it.

Start the conversation