Skip to main content

PostgreSQL fe_sendauth in Docker? exec trust vs TCP auth

· 5 min read

On the host that runs the database container, docker exec-ing in and running psql connects with no password at all. Run the same username from another container over TCP and it dies instantly with fe_sendauth: no password supplied.

Encountered this while building AI Ops — LLM-powered analytics that surfaces market trends, user behavior, and sales data for precise operational strategy. Ops scripts inside the orchestration container reach the analytics database cross-container, and a connection string copied from the exec habit tripped on the very first hop.

Symptom: exec connects, TCP answers fe_sendauth: no password supplied​

Same host, same database, same user — two paths, two fates. Verified matrix (Airflow container → PostgreSQL container):

Connection methodResult
docker exec cclhub-db psql -U postgres (in-container socket)Connects, no password
Cross-container TCP, DSN without passwordfe_sendauth: no password supplied
Cross-container TCP, DSN with passwordConnects

If you searched for "fe_sendauth no password supplied", "psql no password error" or "docker postgres connection fails without password" — this is it.

Root cause: socket trust and TCP password auth are two different pg_hba paths​

PostgreSQL authentication is matched line by line in pg_hba.conf by connection type, and the official image ships completely different rules for the two paths:

  • docker exec uses the Unix domain socket, covered by a local all all trust-style rule — local socket is trusted, no password asked;
  • Cross-container traffic is TCP (a host-type rule), and the official image defaults to scram-sha-256 / md5 password auth.

So the no-password habit built on exec turns into "no password at all" the moment you switch to TCP — the literal meaning of fe_sendauth: no password supplied is "the server wants a password and the client supplied none".

Worth separating two often-confused errors: no password supplied means no password was provided; password authentication failed means one was, and it was wrong. The former points at the connection string; the latter at the credential itself — different fixes.

The fix: put the password in the DSN, don't copy the exec habit​

Cross-container scripts use a password-carrying connection string, always:

postgresql://postgres:<password>@<db host>:5432/<db>

The recommended source for the password is the DB container's own environment — the official image's POSTGRES_PASSWORD exists precisely for initialization — avoiding a second hardcode:

PW=$(docker exec cclhub-db printenv POSTGRES_PASSWORD)
psql "postgresql://postgres:${PW}@localhost:5432/postgres" -c "SELECT 1"

Application-side (Python here) it's the same shape, with the DSN in environment management:

import os
import psycopg

DSN = os.environ["APP_DB_DSN"] # postgresql://user:pass@host:5432/db
with psycopg.connect(DSN) as conn:
conn.execute("SELECT 1")

Note that passwords containing reserved characters like @ : / # must be percent-encoded in the URL — another place special characters bite; avoiding them in generated database passwords removes an entire class of trouble.

Boundary cases​

  • The error's shape varies by client: an interactive libpq terminal (psql without -t) first prompts Password for user postgres: and then fails with fe_sendauth; connection pools and GUI tools (pgAdmin) surface it as an auth failure in the UI — different texts, same root cause.
  • .pgpass files and the PGPASSWORD environment variable are two alternative ways to supply the password; in containerized setups, DSN/env injection is more common than mounting a .pgpass file.
  • You can set pg_hba to trust for TCP too — technically possible, and wrong for production: anything that can reach the port gets credential-free access.
  • Auth method version drift: newer official images default to scram-sha-256; very old client libraries may not support it — that's a different error class (unsupported authentication method), not "no password supplied".

Watch out

  • Diagnose the connection path first: socket or TCP, and which pg_hba rule it matches, decides whether a password is even requested — don't generalize exec behavior to everything.
  • Keep the error semantics straight: no password supplied (missing) and authentication failed (wrong) lead to completely different fixes.
  • Avoid or percent-encode special characters in DSN passwords — URL reserved characters silently change how the string parses.

FAQ​

What does fe_sendauth: no password supplied mean?​

The server's pg_hba.conf requires password auth, but the client's connection string carries no password. It is not "wrong password" (that's authentication failed) — it's "no password at all"; check whether the DSN is missing its password part.

Why does docker exec psql connect without a password?​

Inside the container psql uses the Unix domain socket, which pg_hba covers with a trust rule; cross-container traffic is TCP and hits a host rule that demands a password. Same command, different path, completely different auth requirements.

How should containerized scripts connect to PostgreSQL?​

Use a DSN with an explicit password — postgresql://user:password@host:5432/db — read from the DB container's POSTGRES_PASSWORD environment variable. Don't hardcode it and don't expect socket trust to apply over TCP.

CCLEE

Independent developer, 24 years in e-commerce, focused on grounding AI in real business scenarios.

Work with me