All Articles

Docker Compose Container Can't Connect to Database — Fix (2026)

Getting 'connection refused' between Docker Compose containers? Here are the 7 most common causes and how to fix each one, with working examples.

DevOpsBoysApr 15, 20264 min read
Share:Tweet

"Connection refused" between Docker Compose services is one of the most common errors beginners hit. Your app container starts fine but can't reach the database. Here's every cause and fix.

Quick Diagnosis

bash
# Check if all containers are running
docker compose ps
 
# Check container logs
docker compose logs db
docker compose logs app
 
# Test connectivity from inside app container
docker compose exec app ping db
docker compose exec app nc -zv db 5432

Cause 1: Wrong Hostname — Using localhost Instead of Service Name

The most common mistake. In Docker Compose, containers don't connect via localhost — they use the service name as the hostname.

yaml
services:
  db:
    image: postgres:15
  app:
    image: my-app

Your app must use db as the hostname, not localhost:

python
# WRONG
DATABASE_URL = "postgresql://user:pass@localhost:5432/mydb"
 
# CORRECT — use the service name
DATABASE_URL = "postgresql://user:pass@db:5432/mydb"
yaml
# In docker-compose.yml
services:
  app:
    environment:
      DATABASE_URL: "postgresql://user:pass@db:5432/mydb"
                                              # ↑ service name

Cause 2: App Starts Before DB Is Ready

Docker Compose depends_on only waits for the container to start, not for the database inside to be ready to accept connections. PostgreSQL takes 2-5 seconds to initialize.

Symptom:

app_1  | Error: connect ECONNREFUSED 172.18.0.2:5432
db_1   | LOG:  database system is ready to accept connections
# (db becomes ready after app already crashed)

Fix 1: Use healthcheck with depends_on condition

yaml
services:
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 10s
 
  app:
    image: my-app
    depends_on:
      db:
        condition: service_healthy   # ← wait for healthcheck to pass

Fix 2: Retry logic in your app

python
import time
import psycopg2
 
def connect_with_retry(max_retries=10, delay=2):
    for attempt in range(max_retries):
        try:
            conn = psycopg2.connect(os.environ["DATABASE_URL"])
            print("Connected to database")
            return conn
        except psycopg2.OperationalError:
            print(f"DB not ready, retry {attempt+1}/{max_retries}...")
            time.sleep(delay)
    raise Exception("Could not connect to database")

Cause 3: Not on the Same Network

By default, all services in a docker-compose.yml share one network. But if you have multiple Compose files or custom network configs, services might be isolated.

Check networks:

bash
docker network ls
docker inspect <container_id> | grep -A 10 Networks

Fix: Explicitly put services on the same network:

yaml
services:
  db:
    image: postgres:15
    networks:
      - backend
 
  app:
    image: my-app
    networks:
      - backend
 
networks:
  backend:
    driver: bridge

Cause 4: Wrong Port

The container port ≠ the published host port.

yaml
services:
  db:
    image: postgres:15
    ports:
      - "5433:5432"   # host:container
  • From your laptop: connect to localhost:5433
  • From another container: connect to db:5432 (container port, not host port)
yaml
# app container env var
DATABASE_URL: "postgresql://user:pass@db:5432/mydb"
#                                        ↑ 5432, NOT 5433

Cause 5: Database Didn't Initialize Properly

PostgreSQL silently fails to initialize if the data directory already has data with a different password.

bash
# Check db logs for initialization errors
docker compose logs db | head -50
 
# Common error:
# FATAL: data directory "/var/lib/postgresql/data" has wrong ownership
# FATAL: password authentication failed for user "postgres"

Fix: Remove the volume and restart

bash
docker compose down -v   # WARNING: deletes all data
docker compose up -d

If you want to keep data, check volume permissions:

bash
docker compose exec db ls -la /var/lib/postgresql/

Cause 6: App Connecting to Host, Not Container

If your app is running on the host machine (not in Docker) but the DB is in Docker:

bash
# Expose DB port to host
services:
  db:
    ports:
      - "5432:5432"   # now reachable from host

And from host: localhost:5432 works. But from inside another container, you need db:5432.


Cause 7: Environment Variables Not Set Correctly

YAML indentation errors or wrong env var names:

yaml
# WRONG — environment is a sibling of image, not inside
services:
  app:
    image: my-app
  environment:         # ← wrong indentation
    DB_HOST: db
 
# CORRECT
services:
  app:
    image: my-app
    environment:       # ← under app
      DB_HOST: db

Check env vars are actually set:

bash
docker compose exec app env | grep DB

Full Working Example

yaml
# docker-compose.yml
services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: secret123
      POSTGRES_DB: myapp
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 15s
    networks:
      - app-network
 
  app:
    build: .
    environment:
      DATABASE_URL: "postgresql://appuser:secret123@db:5432/myapp"
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "3000:3000"
    networks:
      - app-network
 
volumes:
  db-data:
 
networks:
  app-network:

Debug Checklist

bash
# 1. Are all containers running?
docker compose ps
 
# 2. Can app reach db by hostname?
docker compose exec app ping -c 3 db
 
# 3. Is the port actually open?
docker compose exec app nc -zv db 5432
 
# 4. What do the db logs say?
docker compose logs db --tail=50
 
# 5. Is the env var set correctly in app?
docker compose exec app env | grep -i db
 
# 6. What network are they on?
docker compose exec app cat /etc/hosts

Resources

Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments