DeployEasy
DockerBeginner

Docker Compose Ignores .env and PostgreSQL Says Password Authentication Failed

Understand .env, env_file, and environment in Docker Compose, inspect variables inside a container, and fix PostgreSQL passwords when a volume already exists.

· 3 min read· 476 words
Table of contents

Two related mistakes cause many Docker Compose database failures: assuming every .env value is automatically inside every container, and changing POSTGRES_PASSWORD while expecting an existing PostgreSQL volume to change its password.

The fix is to understand which layer reads each variable and whether PostgreSQL is being initialized for the first time.

.env, env_file, and environment are different

Compose uses the project .env file for interpolation in compose.yaml:

services:
  api:
    environment:
      DATABASE_URL: ${DATABASE_URL}

env_file passes variables into a container:

services:
  api:
    env_file:
      - .env.production

environment is explicit and can override values from env_file. Do not confuse Compose interpolation on the host with the container’s runtime environment.

Check the resolved configuration

docker compose config
docker compose config --environment

Look for an empty value, an unexpected project directory, or a variable name that does not match the application code. Be careful: rendered configuration can reveal secrets in terminal output.

Check the container’s environment

docker compose exec api printenv | sort
docker compose exec api sh -lc 'printf "%s\n" "$DATABASE_URL"'

If a variable is missing, check the service’s env_file path, the current directory, and whether the app uses the same variable name.

Why changing POSTGRES_PASSWORD may not work

The official PostgreSQL image uses POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB during the first initialization of an empty data directory. Once the volume contains a database, changing the Compose variable does not rewrite the existing role password.

Confirm the service and volume:

docker compose ps
docker volume ls
docker compose logs db --tail=100

If you still know a superuser password, connect and alter the application role:

docker compose exec db psql -U postgres -d postgres
ALTER ROLE app_user WITH PASSWORD 'use-a-new-secret-here';

Update the application’s DATABASE_URL, restart the API, and test a real query.

Recreate only disposable development data

docker compose down -v
docker compose up -d

The -v flag removes project volumes and can permanently delete database data. Never use it in production without a verified backup and explicit approval.

Use the Compose service name

Inside the Compose network, use db:5432, not localhost:5432. localhost inside the API container points back to the API container itself.

services:
  api:
    environment:
      DATABASE_URL: postgresql://app_user:${POSTGRES_PASSWORD}@db:5432/app
  db:
    environment:
      POSTGRES_USER: app_user
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: app

Debugging checklist

  1. Render docker compose config and inspect the resolved values.
  2. Confirm the API container received the expected variable.
  3. Confirm the database is healthy and listening.
  4. Confirm the hostname is the Compose service name.
  5. Confirm the user, database, and password belong to the same initialized cluster.
  6. Check whether a persistent volume predates the current .env file.
  7. Test from the API container, not only from the host.

env_file passes variables to a container, but it does not change credentials in an already initialized PostgreSQL volume.

Continue reading