DEV Community

Chandan Gupta
Chandan Gupta

Posted on

🐳 Fixing “FATAL: database does not exist” in PostgreSQL Docker (Healthcheck Mistake)

💡 Quick Stats

  • Series: Docker
  • Difficulty: Beginner / Intermediate
  • Read Time: 5 min

🚀 The Setup

I was building a .NET 8 Web API with PostgreSQL using Docker Compose.

Everything looked fine:

  • Containers were running
  • Migrations were applied
  • API was responding
  • Database was created

But PostgreSQL logs were spamming this every 5 seconds:

FATAL: database "train_user" does not exist
Enter fullscreen mode Exit fullscreen mode

The strange part?
The API was working perfectly.

So why was PostgreSQL complaining?


🧱 My Docker Setup

Here’s the relevant docker-compose.yml:

services:
  postgres:
    image: postgres:16
    container_name: train-postgres
    environment:
      POSTGRES_DB: train_db
      POSTGRES_USER: train_user
      POSTGRES_PASSWORD: train_pass
    ports:
      - "5433:5432"
    volumes:
      - train_pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U train_user"]
      interval: 5s
      timeout: 5s
      retries: 5

  api:
    build: .
    container_name: train-api
    ports:
      - "8080:8080"
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      ConnectionStrings__DefaultConnection: "Host=postgres;Port=5432;Database=train_db;Username=train_user;Password=train_pass"

volumes:
  train_pgdata:
Enter fullscreen mode Exit fullscreen mode

Looks correct at first glance, right?


🔎 The Clue

The error appeared exactly every 5 seconds.

That matched this line:

interval: 5s
Enter fullscreen mode Exit fullscreen mode

That meant something inside the healthcheck was failing.


🧠 Understanding PostgreSQL Default Behavior

The healthcheck command was:

pg_isready -U train_user
Enter fullscreen mode Exit fullscreen mode

Here’s the important PostgreSQL rule:

If you don’t specify a database, PostgreSQL assumes:
Database name = Username

So this command was actually trying to connect to:

Database: train_user
Enter fullscreen mode Exit fullscreen mode

But my actual database (created using POSTGRES_DB) was:

train_db
Enter fullscreen mode Exit fullscreen mode

That mismatch caused:

FATAL: database "train_user" does not exist
Enter fullscreen mode Exit fullscreen mode

Every 5 seconds.


✅ The Fix

Simply specify the correct database in the healthcheck:

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U train_user -d train_db"]
  interval: 5s
  timeout: 5s
  retries: 5
Enter fullscreen mode Exit fullscreen mode

Restart containers:

docker compose down
docker compose up --build
Enter fullscreen mode Exit fullscreen mode

And the log spam disappeared instantly.


🎯 Key Lessons

1️⃣ Container Name ≠ Database Name

Type Example
Container name train-postgres
Service name (Docker DNS) postgres
Database name train_db

They are three completely different things.


2️⃣ PostgreSQL Defaults Can Trick You

If you connect without -d, PostgreSQL uses:

Database = Username
Enter fullscreen mode Exit fullscreen mode

Always specify the database explicitly.


3️⃣ Healthchecks Can Mislead You

A failing healthcheck can:

  • Spam logs
  • Confuse debugging
  • Make you suspect the wrong issue
  • Hide the real root cause

Timing patterns in logs are powerful debugging clues.


🏁 Final State

After the fix:

  • PostgreSQL container → Healthy
  • .NET API → Running
  • Database → Correct
  • Logs → Clean
  • No more FATAL errors

💡 Bonus Improvement

You can make the healthcheck dynamic:

test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
Enter fullscreen mode Exit fullscreen mode

This avoids hardcoding values.


🔥 Final Thought

This wasn’t a Docker problem.

It was:

  • A PostgreSQL default behavior
  • Combined with a small configuration oversight

Sometimes debugging is just about understanding how tools behave by default.


If this helped you, feel free to connect or share your experience debugging Docker setups 👋

Top comments (0)