lenec ru

← все посты

ECONNREFUSED 127.0.0.1:5432 — Postgres не отвечает, что делать

10K

Сообщение Error: connect ECONNREFUSED 127.0.0.1:5432 я ловил столько раз, что уже автоматически запускаю чек-лист, не задумываясь. Объясню, что значит ошибка, и пройдусь по всем причинам, которые встречал на практике.

Что говорит ошибка

Твой Node-клиент пытается открыть TCP-соединение на 127.0.0.1:5432. Но операционная система ответила «connection refused» — никто не слушает этот порт. То есть Postgres-а на этом адресе нет, или он не отвечает на TCP, или firewall режет.

Нюанс: это не ошибка авторизации. Авторизация — это password authentication failed. Это не ошибка таймаута. Таймаут — это ETIMEDOUT. Refused — конкретно «никого нет дома».

Шаг 1: запущен ли Postgres вообще

На своей машине:

sudo systemctl status postgresql
# или
sudo systemctl status postgresql@16-main

На macOS с Homebrew:

brew services list
# и при необходимости
brew services start postgresql@16

В Docker:

docker ps | grep postgres
# если контейнер упал
docker logs <container>

Если Postgres не запущен — запусти. Большинство «у меня всё было нормально вчера» лечится буквально brew services start.

Шаг 2: на каком порту слушает

Postgres по умолчанию на 5432, но не всегда. Проверь:

sudo ss -tnlp | grep -E '5432|5433'
# или netstat
sudo netstat -tnlp | grep -E '5432|5433'

Если у тебя на машине несколько кластеров (5432 и 5433) — может быть, ты подключаешься не к тому. Особенно часто бывает на Ubuntu, где после апгрейда старый кластер остаётся слушать рядом.

Шаг 3: какой именно адрес слушает

Postgres может слушать только Unix-сокет, не TCP. Проверь postgresql.conf:

sudo grep -E 'listen_addresses|port' /etc/postgresql/16/main/postgresql.conf

Должно быть что-то такое:

listen_addresses = 'localhost'
port = 5432

Если listen_addresses = '' — Postgres слушает только Unix-сокеты, по TCP не доступен. Поправь и сделай systemctl restart postgresql.

Шаг 4: pg_hba.conf не блокирует ли

Если TCP-соединение приняли, но потом сразу разорвали, это уже не ECONNREFUSED, а ECONNRESET. Но если pg_hba настроен жёстко, и для localhost нет правила, Postgres вообще может не слушать на твоём интерфейсе. Проверь:

sudo cat /etc/postgresql/16/main/pg_hba.conf

Должна быть строка типа:

host all all 127.0.0.1/32 md5

Шаг 5: правильный ли порт в коде

Самое глупое, но самое частое. Проверь DATABASE_URL:

echo $DATABASE_URL
# или
cat .env | grep DATABASE_URL

Бывает, что в .env 5432, а контейнер с Postgres слушает на 5433 (потому что 5432 занят локальной установкой). Бывает, что в docker compose ты пробросил 5433:5432, и из приложения внутри контейнера надо ходить на 5432, а из хост-системы — на 5433.

Шаг 6: правильный ли host

В Docker Compose сервис называется по имени. Из контейнера приложения хост Postgres-сервиса — postgres, не localhost:

DATABASE_URL=postgres://app:app@postgres:5432/app

Если ты пишешь localhost внутри контейнера — это localhost самого контейнера, в нём Postgres-а нет.

Шаг 7: firewall

На VPS проверь UFW и iptables:

sudo ufw status
sudo iptables -L INPUT -n | grep 5432

Для localhost обычно ничего не нужно. Если ходишь снаружи на удалённый Postgres — открыть 5432 в файрволе.

Шаг 8: managed Postgres и SSL

На managed-Postgres (Yandex Managed, Selectel Cloud Database, RDS) часто требуется SSL. Без него соединение тоже может сразу отвергаться (в зависимости от настроек). В строке подключения добавь ?sslmode=require:

DATABASE_URL=postgres://app:app@host:5432/app?sslmode=require

Прибавляется к строке подключения, и драйвер pg сам поднимет TLS.

Шаг 9: connection limits

Если Postgres работает, но новых клиентов уже не принимает (упёрся в max_connections), на новый коннект ты можешь увидеть и таймаут, и иногда reset. Проверь:

SELECT count(*), state FROM pg_stat_activity GROUP BY state;

Если число близко к max_connections — есть проблема: где-то соединения утекают. Лекарство — pgbouncer как пулер или строгий пулинг на стороне приложения.

Шаг 10: разный сетевой стек

На некоторых системах localhost резолвится в ::1 (IPv6), и Postgres может слушать только IPv4. Это редкая ситуация в Linux, но иногда встречается на macOS. Попробуй явно 127.0.0.1 вместо localhost в строке подключения.

Полный чек-лист на 30 секунд

  1. systemctl status postgresql — запущен?
  2. ss -tnlp | grep 5432 — слушает порт?
  3. echo $DATABASE_URL — правильный host/port?
  4. Если Docker — host = имя сервиса, а не localhost.
  5. Если managed — добавлен ли sslmode=require?
  6. Если на проде вдруг — нет ли утечки коннектов?

Превентивные меры

Health check на старте приложения

async function waitForDb(timeout = 30_000) {
  const start = Date.now();
  while (Date.now() - start < timeout) {
    try {
      await db.execute(sql`select 1`);
      return;
    } catch (e) {
      console.log('waiting for db...');
      await new Promise(r => setTimeout(r, 1000));
    }
  }
  throw new Error('Database is not reachable');
}

На старте приложения ждёшь, пока БД не отзовётся. Полезно в Docker Compose, где приложение стартует чуть быстрее, чем postgres готов.

Connection pool с лимитом

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
  idleTimeoutMillis: 30_000,
  connectionTimeoutMillis: 5_000,
});

connectionTimeoutMillis: 5000 ограничивает время ожидания свободного коннекта. Без него на загруженном пуле приложение может зависнуть на ECONNREFUSED-подобной ошибке надолго.

Алерты

Поставь алерт «БД недоступна» — на твоём health-check endpoint. Если возвращает 503 больше двух минут — пинг тебе.

Что НЕ делать

  • Не пытайся «обернуть в try/catch и ретрай тысячу раз» как первое решение. Сначала пойми, почему БД не отвечает.
  • Не открывай 5432 в интернет, если можно ходить через приватную сеть или туннель.
  • Не ставь огромный max_connections: если упёрся — это симптом, не причина.

ECONNREFUSED — частая, но безобидная ошибка, если знаешь, где смотреть. Чек-лист выше у меня всегда наготове, и обычно за минуту-две я выясняю, что не так. Чаще всего это банальный «забыл запустить контейнер» или «.env смотрит на не тот порт».

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.