Перейти к содержимому
← Все заметки

// заметки

PostgreSQL: connection refused — не подключается

Connection refused и no pg_hba.conf entry выглядят похоже, но лежат на разных уровнях. Разбираю диагностику, причины и фиксы для локального PostgreSQL и Docker

Опубликовано: 2026-10-095 мин чтения
PostgreSQLconnection-refusedDockerpg_hbaLinux

PostgreSQL отказывает в подключении: psql отвечает Connection refused или FATAL: no pg_hba.conf entry. Эти две ошибки лежат на разных уровнях, и лечить их нужно по-разному. Ниже — как за пару команд понять, в чём дело: сервис не запущен, слушает не тот адрес, занят порт, не опубликован порт в Docker или соединение отклоняет pg_hba.conf. Для каждой причины — свой фикс

Симптом

Клиент падает на сетевом уровне, когда до порта никто не слушает

$ psql -h 127.0.0.1 -p 5432 -U app -d appdb
psql: error: connection to server at "127.0.0.1", port 5432 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?

Другая ошибка означает, что сервер ответил, но закрыл соединение по своим правилам

$ psql "postgresql://app@db.example.com:5432/appdb"
psql: error: connection to server at "db.example.com" (203.0.113.10), port 5432 failed:
FATAL:  no pg_hba.conf entry for host "203.0.113.10", user "app", database "appdb", no encryption

Первая ошибка — сетевой уровень: пакет пришёл, слушателя нет. Вторая — уровень аутентификации: сервер доступен, но pg_hba.conf не пропускает конкретного пользователя. Перепутать их дорого: правка pg_hba.conf не поднимет остановленный процесс, а перезапуск сервиса не отменит правила аутентификации

Диагностика

Первая команда — pg_isready. Она стучится в порт и возвращает код выхода: 0 — принимает соединения, 1 — отклоняет, 2 — не отвечает, 3 — попытка не сделана (неверные параметры подключения). Если утилита не найдена, смотрите разбор Linux: command not found

$ pg_isready -h 127.0.0.1 -p 5432
127.0.0.1:5432 - accepting connections
$ echo $?
0

Дальше смотрим, кто и на каком адресе слушает порт

$ ss -lntp | grep 5432
LISTEN 0 244 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=1234,fd=6))

127.0.0.1:5432 — только loopback, 0.0.0.0:5432 — все интерфейсы, пустой вывод — не слушает никто. Unix-сокет виден отдельно

$ ss -lxnp | grep PGSQL
u_str LISTEN 0 244 /var/run/postgresql/.s.PGSQL.5432 12345 * 0 users:(("postgres",pid=1234,fd=6))

Состояние сервиса зависит от способа установки. В Debian и Ubuntu мета-юнит postgresql.service может быть active (exited), пока реальный кластер лежит, поэтому проверяем сам кластер

$ systemctl status postgresql --no-pager
● postgresql.service - PostgreSQL RDBMS
     Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; preset: enabled)
     Active: active (exited) since ...

$ pg_lsclusters
Ver Cluster Port Status Owner    Data directory                    Log file
16  main    5432 down   postgres /var/lib/postgresql/16/main       /var/log/postgresql/postgresql-16-main.log

Для сборок без systemd статус показывает pg_ctl

$ pg_ctl status -D "$PGDATA"
pg_ctl: server is running (PID: 1234)

В Docker проверяем публикацию порта и логи. Пустая колонка PORTS означает, что порт не опубликован

$ docker ps
CONTAINER ID   IMAGE         ...   PORTS                    NAMES
a1b2c3d4e5f6   postgres:16   ...   0.0.0.0:5432->5432/tcp   db

$ docker logs --tail 50 db
PostgreSQL init process complete; ready for start up.
LOG:  listening on IPv4 address "0.0.0.0", port 5432
LOG:  database system is ready to accept connections

Если изнутри контейнера сервер принимает соединения, а снаружи Connection refused, проблема в публикации порта, а не в PostgreSQL

$ docker exec -it db pg_isready
/var/run/postgresql:5432 - accepting connections

Причина

Причин несколько, и каждая проверяется отдельно

  • Процесс не запущен или упал на старте: занят порт, недоступен PGDATA, ошибка в конфиге, нет прав на каталог данных
  • listen_addresses = 'localhost' в postgresql.conf: сервер слушает только 127.0.0.1 и не принимает внешние подключения
  • Порт занят или не тот: другой кластер или версия слушает 5432, а клиент идёт на 5433
  • В Docker порт не опубликован: контейнер запущен без -p 5432:5432 либо публикация привязана только к 127.0.0.1
  • Из контейнера обращаются к localhost: там нет хостового PostgreSQL, нужен адрес сервиса или хост-шлюз
  • Firewall режет пакеты: обычно это timeout, а не refusal, но проверить стоит
  • pg_hba.conf не содержит подходящей строки для адреса, пользователя или базы
Connection refused — это TCP RST от ядра: пакет дошёл до хоста, но на порту никто не слушает. Firewall чаще дропает пакет, и клиент видит timeout. Если ошибка именно Connection refused, виновата не фильтрация, а отсутствие слушателя

Отдельно про pg_hba.conf. Это правила: тип подключения, база, пользователь, адрес и метод аутентификации. Если ни одна строка не подошла, сервер отвечает FATAL: no pg_hba.conf entry. Порядок важен: срабатывает первое совпадение

# TYPE   DATABASE  USER  ADDRESS         METHOD
local    all       all                   peer
host     appdb     app   127.0.0.1/32    scram-sha-256
host     appdb     app   10.0.0.0/8      scram-sha-256
host     all       all   ::1/128         scram-sha-256

local — Unix-сокет, host — TCP, hostssl — только TLS. peer сверяет имя пользователя ОС, scram-sha-256 требует пароль. Строки читаются сверху вниз, побеждает первая подходящая

Решение

Разберём по причинам

Не запущен сервис

Запускаем кластер и смотрим журнал. Подставьте своё имя кластера

$ sudo systemctl start postgresql@16-main
$ systemctl status postgresql@16-main --no-pager
$ journalctl -u postgresql@16-main -n 50 --no-pager

Если старт падает, причина в логе. Каталог данных должен принадлежать пользователю postgres и иметь права 700

$ sudo ls -ld /var/lib/postgresql/16/main
drwx------ 3 postgres postgres 4096 ... /var/lib/postgresql/16/main

Сервер слушает только localhost

Правим listen_addresses в postgresql.conf. Параметр читается при старте, поэтому нужен restart, а не reload

# /etc/postgresql/16/main/postgresql.conf
listen_addresses = '*'
$ sudo systemctl restart postgresql@16-main

После рестарта ss -lntp покажет 0.0.0.0:5432 или [::]:5432. Открывать сервер в интернет без firewall и сильного пароля нельзя

Порт занят или другой

Какой порт слушает сам сервер, видно в psql

$ psql -h 127.0.0.1 -p 5432 -d postgres -c 'show port;'
 port
------
 5432

Кто занимает порт и куда ходит клиент, проверяем так

$ sudo ss -lntp 'sport = :5432'
$ sudo lsof -iTCP:5432 -sTCP:LISTEN

Если база на 5433, укажите порт явно: psql -p 5433. Строку подключения в приложении правьте там же, где задан хост

В Docker не опубликован порт

Порт публикуется при создании контейнера, на лету его не меняют

$ docker run -d --name db -p 127.0.0.1:5432:5432 \
    -e POSTGRES_PASSWORD='<password>' postgres:16

В Compose то же самое описывает секция ports

services:
  db:
    image: postgres:16
    ports:
      - "127.0.0.1:5432:5432"
    environment:
      POSTGRES_PASSWORD: "<password>"

-p 127.0.0.1:5432:5432 публикует порт только на loopback хоста, -p 5432:5432 — на все интерфейсы. Для локальной разработки хватит первого

Подключение к localhost из контейнера

Внутри контейнера localhost указывает на сам контейнер. Если база в соседнем сервисе Compose, используйте его имя

# вместо postgresql://app@localhost:5432/appdb
postgresql://app@db:5432/appdb

Если база на хосте, в Linux добавьте шлюз: docker run --add-host=host.docker.internal:host-gateway. Надёжнее всё же держать базу сервисом в той же сети Compose

Firewall

Внешние подключения фильтруются на хосте и в облачной панели. Открывайте порт точечно

$ sudo ufw allow from 203.0.113.0/24 to any port 5432 proto tcp
$ sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" port port="5432" protocol="tcp" accept'

Помните про симптом: Connection refused — это не firewall. Сначала убедитесь, что порт слушается, и только потом трогайте фильтры

Правила pg_hba

Добавьте строку под своего пользователя и перечитайте правила. pg_hba.conf применяется без рестарта

# /etc/postgresql/16/main/pg_hba.conf
host    appdb    app    10.0.0.0/8    scram-sha-256
$ sudo -u postgres psql -c 'select pg_reload_conf();'
 pg_reload_conf
----------------
 t

Метод trust пропускает без пароля и годится только для локальной разработки. peer работает для Unix-сокета и сверяет имя пользователя ОС

Разбор установки и первичной настройки базы с нуля — в отдельной заметке: PostgreSQL: установка и настройка

Проверка

Проверяем по слоям: сначала порт, потом аутентификация

$ pg_isready -h 127.0.0.1 -p 5432
127.0.0.1:5432 - accepting connections

$ psql "postgresql://app@127.0.0.1:5432/appdb" -c 'select 1;'
 ?column?
----------
        1
(1 row)

Из контейнера

$ docker exec -it db pg_isready
/var/run/postgresql:5432 - accepting connections

И финальная проверка с явными параметрами

$ psql -h 127.0.0.1 -p 5432 -U app -d appdb -c '\conninfo'
You are connected to database "appdb" as user "app" on host "127.0.0.1" at port "5432".

Если select 1 отдаёт строку, а приложение всё равно падает, дело уже не в сети: сверьте строку подключения и переменные окружения сервиса

Подводные камни

  • Unix-сокет и TCP — разные каналы. psql без -h идёт в /var/run/postgresql, а psql -h localhost — по TCP. Сервер может принимать сокет и отказывать по сети: правила local и host независимы
  • `peer` для локальных подключений. В Debian и Ubuntu local all all peer сверяет имя пользователя ОС. psql -U postgres под обычным пользователем даст Peer authentication failed, нужен sudo -u postgres psql
  • `localhost` может резолвиться в IPv6. Если сервер слушает только 127.0.0.1, а localhost превращается в ::1, клиент получит Connection refused. Указывайте 127.0.0.1 явно
  • `PGDATA` задаёт, какой кластер читать. При ручном запуске неверный путь поднимает пустой или чужой кластер. Проверяйте: pg_ctl status -D "$PGDATA"
  • Несколько кластеров на одном порту. На Debian и Ubuntu это покажет pg_lsclusters, победит тот, кто занял порт первым
  • `pg_hba.conf` читается сверху вниз. Строка host all all 0.0.0.0/0 trust выше вашей обнулит остальные правила

Итог

Connection refused лечится проверкой слушателя: процесс не запущен, не тот адрес, не опубликован порт. no pg_hba.conf entry — это уже правила, и сервер доступен по сети. Порядок диагностики: pg_isready, затем ss -lntp, затем pg_hba.conf

Если база должна работать под нагрузкой и без сюрпризов, а не крутиться только на ноутбуке, помогут консалтинг по PostgreSQL и разработка backend

Нужно решить такую задачу на вашем проекте?