medusajs/medusa · critical · Error

Failed to establish a connection to PostgreSQL. Please ensur

Error message

Failed to establish a connection to PostgreSQL. Please ensure the following is true and try again:
      - You have a PostgreSQL database running
      - You have passed the correct credentials in medusa-config.js
      - You have formatted the database connection string correctly. See below:
      "postgres://[username]:[password]@[host]:[port]/[db_name]" - If there is no password, you can omit it from the connection string
      ${EOL}
      ${err.message}

What it means

Maps PostgreSQL connection-failure errors (e.g. ECONNREFUSED) into a checklist message. It means Medusa could not open a TCP connection to the Postgres server at all.

Source

Thrown at packages/core/utils/src/common/handle-postgres-database-error.ts:19

import { EOL } from "os"

export const DatabaseErrorCode = {
  databaseDoesNotExist: "3D000",
  connectionFailure: "ECONNREFUSED",
  wrongCredentials: "28000",
  notFound: "ENOTFOUND",
  migrationMissing: "42P01",
}

export function handlePostgresDatabaseError(err: any): never {
  if (DatabaseErrorCode.databaseDoesNotExist === err.code) {
    throw new Error(
      `The specified PostgreSQL database does not exist. Please create it and try again.${EOL}${err.message}`
    )
  }

  if (DatabaseErrorCode.connectionFailure === err.code) {
    throw new Error(
      `Failed to establish a connection to PostgreSQL. Please ensure the following is true and try again:
      - You have a PostgreSQL database running
      - You have passed the correct credentials in medusa-config.js
      - You have formatted the database connection string correctly. See below:
      "postgres://[username]:[password]@[host]:[port]/[db_name]" - If there is no password, you can omit it from the connection string
      ${EOL}
      ${err.message}`
    )
  }

  if (DatabaseErrorCode.wrongCredentials === err.code) {
    throw new Error(
      `The specified credentials does not exists for the specified PostgreSQL database.${EOL}${err.message}`
    )
  }

  if (DatabaseErrorCode.notFound === err.code) {
    throw new Error(

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Start PostgreSQL and verify with `pg_isready -h host -p port`
  2. Correct host/port/credentials in the connection string
  3. Add retry/wait-for-db (depends_on with condition: service_healthy) in docker-compose

Example fix

# docker-compose before
services:
  api:
    depends_on: [db]
# after
services:
  api:
    depends_on:
      db: { condition: service_healthy }
  db:
    healthcheck: { test: ["CMD","pg_isready"], interval: 5s }
Defensive patterns

Strategy: retry

Validate before calling

// preflight
const net = require('net')
await new Promise((res, rej) => { const s = net.connect(port, host, () => (s.destroy(), res()))
  s.on('error', rej) })

Try / catch

for (let i = 0; i < 5; i++) { try { return await connect() } catch (e) { if (/Failed to establish a connection/.test(e.message)) await sleep(2000 * (i + 1)); else throw e } } throw lastError

Prevention

When it happens

Trigger: Postgres not running, wrong host/port in DATABASE_URL, firewall/DNS issues, or docker-compose where the app starts before the db service is ready.

Common situations: Local dev without postgres started, wrong port (5433 vs 5432), container networking (localhost vs service name), or transient startup races in CI.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/08168cb78009666d. Report an issue: GitHub.