/인프라/no pg_hba.conf entry·password authentication failed 원인별 해결법
인프라PostgreSQLpg_hba.conf

no pg_hba.conf entry·password authentication failed 원인별 해결법

PostgreSQL 접속 에러 6종을 네트워크·pg_hba·인증 3계층으로 30초 만에 판정하는 방법. 에러 원문 대조표, ss·pg_hba_file_rules 진단 명령, 첫 매치 규칙, PG14 scram-sha-256 전환 복구, Docker·K8s·RDS 분기까지 정리했습니다.

no pg_hba.conf entry·password authentication failed 원인별 해결법

에러 메시지를 읽는 순서가 틀려서 30분을 날린다

장애 상황에서 가장 자주 반복되는 오진 패턴은 두 가지입니다.

  • FATAL: no pg_hba.conf entry for host ...를 보고 방화벽·보안그룹을 30분 동안 뒤진다.
  • could not connect to server: Connection refused를 보고 pg_hba.conf를 열어 0.0.0.0/0 trust를 추가한다.

둘 다 계층을 잘못 짚은 경우입니다. PostgreSQL 접속은 아래 세 단계를 순서대로 통과합니다.

  1. TCP 도달 — 클라이언트 패킷이 postmaster가 listen 중인 소켓까지 도착하는가
  2. pg_hba 룰 매칭 — 접속 정보(TYPE/DB/USER/소스IP)와 일치하는 라인이 있는가
  3. 인증 검증 — 매칭된 라인의 METHOD로 자격 증명이 통과하는가

중요한 사실은 각 단계가 서로 다른 문구를 낸다는 점입니다. 즉 에러 원문 자체가 이미 "몇 번 단계에서 떨어졌는지"를 알려주고 있습니다. Connection refused가 떴다면 서버는 아직 여러분의 요청을 본 적도 없으므로 pg_hba.conf 수정은 100% 무의미하고, password authentication failed가 떴다면 pg_hba 라인은 이미 매칭에 성공한 상태이므로 pg_hba를 더 만지는 건 시간 낭비입니다.

이 글은 PostgreSQL 12~17, Linux(Debian/Ubuntu·RHEL 계열) 및 Docker/Kubernetes/관리형 DB 환경을 대상으로, 에러 원문 → 계층 → 첫 명령을 30초 안에 매핑하는 절차를 정리합니다.

에러 원문 대조표: 6종 메시지를 3계층에 매핑한다

먼저 지금 보고 있는 에러를 아래 표에서 찾으세요. 해당 행의 "첫 확인 명령"만 실행하면 됩니다.

#에러 원문계층첫 확인 명령흔한 오진 방향
(a)psql: error: could not connect to server: Connection refused ... Is the server running on host "10.0.3.10" and accepting TCP/IP connections on port 5432?네트워크ss -lntp | grep 5432pg_hba.conf 편집 (무의미)
(b)FATAL: no pg_hba.conf entry for host "10.0.3.51", user "app", database "prod", SSL offpg_hbaSELECT * FROM pg_hba_file_rules;방화벽/보안그룹 점검
(c)FATAL: no pg_hba.conf entry for host "10.0.3.51", user "app", database "prod", SSL onpg_hba동일 + hostnossl 라인 확인"SSL을 꺼야 하나" 삽질
(d)FATAL: password authentication failed for user "app"인증SELECT rolname, substring(rolpassword,1,4) FROM pg_authid;pg_hba 재편집 (이미 통과함)
(e)psql: error: FATAL: Peer authentication failed for user "app"인증 + 로컬 소켓psql -h 127.0.0.1 -U app -d prod비밀번호 재설정 반복
(f)FATAL: sorry, too many clients already세션 슬롯 (범위 밖)SHOW max_connections;이미 pg_hba·인증 통과 상태

몇 가지 해석 규칙을 못 박아 둡니다.

(a) 네트워크 계층. 서버 프로세스가 죽었거나, listen_addresseslocalhost이거나, 방화벽/보안그룹/컨테이너 포트 매핑에서 막힌 상태입니다. 로컬 루프백에서 같은 증상이 나오는 경우의 일반 디버깅 절차는 connection refused / ECONNREFUSED 127.0.0.1 30초 진단 런북에 정리되어 있으니 그쪽을 먼저 보세요. 여기서는 PostgreSQL 고유 항목만 다룹니다.

(b)와 (c)의 SSL off / SSL on은 원인이 아니라 "접속 방식 기록"입니다. 서버가 "이 접속은 평문/TLS였다"고 사실을 진술하는 것뿐입니다. 그래서 해석은 정반대가 됩니다.

  • SSL off → 클라이언트가 평문으로 붙었는데 서버에는 hostssl 라인만 있다. → 클라이언트에 sslmode=require를 주거나 host 라인을 만든다.
  • SSL on → TLS로 붙었는데 hostnossl만 있거나, ADDRESS CIDR가 실제 소스 IP를 포함하지 않는다.

두 경우 모두 "매칭되는 라인이 하나도 없다"는 같은 결론이며, 차이는 어떤 TYPE의 라인을 만들어야 하느냐에 있습니다.

(d)는 pg_hba가 이미 통과했다는 증거입니다. 매칭된 라인의 METHOD(scram-sha-256/md5)로 인증을 시도했고 실패한 것이므로, 분기는 ①비밀번호 오타 ②해시 알고리즘 불일치 ③롤 미존재 셋뿐입니다.

(e)는 -h 없이 붙어 유닉스 소켓 경로를 탄 경우입니다. peer 인증은 OS 계정명과 DB 롤명이 같아야 통과합니다. psql -h 127.0.0.1로 바꿔 증상이 달라지면 즉시 확진입니다.

(f)는 이 글의 범위 밖입니다. 판정 정보 한 줄만: 이 메시지가 나왔다는 건 네트워크·pg_hba·인증을 모두 통과했다는 뜻입니다. 원인과 복구는 PostgreSQL too many clients already 30초 판정 복구 런북PostgreSQL 'too many clients already' 5분 진단부터 PgBouncer 해결까지를 참고하세요.

3계층 진단 순서: 명령 6개로 원인 위치를 확정한다

표에서 계층을 좁혔다면 아래 고정 시퀀스를 순서대로 실행합니다. 각 명령마다 예상 정상 출력다를 때의 분기를 붙였습니다.

1단계 — ss -lntp로 리슨 소켓 확인 (서버에서 실행)

Bash
sudo ss -lntp | grep 5432

예상 출력(원격 접속 가능 상태):

CODE
LISTEN 0  244  0.0.0.0:5432  0.0.0.0:*  users:(("postgres",pid=1234,fd=7))
LISTEN 0  244     [::]:5432     [::]:*  users:(("postgres",pid=1234,fd=7))

분기:

  • 127.0.0.1:5432만 보인다 → 원격 접속 불가 확정. listen_addresses='localhost' 상태이며 pg_hba를 아무리 고쳐도 (a) 에러가 계속됩니다.
  • 아무 줄도 없다 → 서버가 죽었거나 다른 포트. systemctl status postgresql / journalctl -u postgresql -n 50.

2단계 — 구동 중 프로세스의 실제 값 확인

설정 파일을 눈으로 읽는 대신 반드시 실행 중 값을 조회하세요. listen_addresses를 고치고 reload만 하면 값이 반영되지 않기 때문에, 파일과 실제 값이 어긋난 상태가 흔합니다.

SQL
SHOW listen_addresses;
SHOW port;
SHOW hba_file;
SHOW config_file;

예상 출력:

CODE
 listen_addresses
------------------
 *

 port
------
 5432

              hba_file
-------------------------------------
 /etc/postgresql/16/main/pg_hba.conf

분기: hba_file 경로가 여러분이 편집한 파일과 다르면 그 자체가 원인입니다. 패키지 설치본은 /etc/postgresql/<major>/main/, 소스 빌드·RHEL 계열은 /var/lib/pgsql/<major>/data/, 공식 Docker 이미지는 /var/lib/postgresql/data/pg_hba.conf를 씁니다.

3단계 — 원격에서 실제 접속 시도

Bash
psql "host=10.0.3.10 port=5432 user=app dbname=prod sslmode=prefer" -c 'select 1'

여기서 나온 에러 원문을 다시 2장 표에 대입합니다. 이 시점부터는 추측이 아니라 표 기반 판정입니다.

4단계 — 서버 로그에 기록된 실제 소스 IP 확인

SQL
ALTER SYSTEM SET log_connections = on;
SELECT pg_reload_conf();

로그 예시:

CODE
2026-08-25 10:12:33 KST [2311] LOG:  connection received: host=10.0.7.88 port=51422
2026-08-25 10:12:33 KST [2311] FATAL:  no pg_hba.conf entry for host "10.0.7.88", user "app", database "prod", SSL off

분기: 서버가 기록한 IP가 여러분이 아는 클라이언트 IP와 다르다면 LB/NAT/사이드카가 소스 IP를 치환한 것입니다. 뒤의 "환경별 분기"로 바로 점프하세요. IP 기반 룰 디버깅은 로그에 찍힌 IP가 진실입니다.

5단계 — 룰 파싱 결과를 SQL로 확인 (PG 10+)

SQL
SELECT line_number, type, database, user_name, address, netmask, auth_method, error
FROM pg_hba_file_rules
ORDER BY line_number;

예상 출력:

CODE
 line_number |  type   | database | user_name |  address  |    netmask    |  auth_method   | error
-------------+---------+----------+-----------+-----------+---------------+----------------+-------
          89 | local   | {all}    | {all}     |           |               | peer           |
          92 | host    | {all}    | {all}     | 127.0.0.1 | 255.255.255.0 | scram-sha-256  |
          95 | host    | {prod}   | {app}     | 10.0.3.0  | 255.255.255.0 | scram-sha-256  |

분기: error 컬럼이 NULL이 아니면 그 줄은 로드되지 않았습니다. 오타·잘못된 CIDR·존재하지 않는 METHOD가 대표 원인입니다. 다음 쿼리를 습관처럼 돌리세요.

SQL
SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;

pg_hba.conf 문법과 첫 매치 규칙: 넓은 reject 한 줄이 전체를 무력화한다

라인 문법은 다음과 같습니다.

CODE
TYPE  DATABASE  USER  ADDRESS  METHOD  [OPTIONS]

TYPE 값의 의미와 (b)(c) 에러의 연결:

TYPE대상관련 에러
local유닉스 도메인 소켓 (-h 미지정)(e) Peer authentication failed
hostTCP, 평문·TLS 모두 매칭(b)(c) 양쪽 모두 해결 가능
hostsslTLS 접속만 매칭SSL off로 붙으면 (b) 발생
hostnossl평문 접속만 매칭TLS로 붙으면 (c) 발생

ADDRESS는 CIDR 표기(10.0.3.0/24, 10.0.3.51/32)를 쓰며, all·samehost·samenet 키워드도 사용할 수 있습니다.

첫 매치 우선 규칙

PostgreSQL은 파일을 위에서부터 스캔하다 처음 매치되는 라인에서 멈추고, 그 라인의 METHOD로 인증합니다. 실패해도 아래 라인으로 내려가지 않습니다. 이 규칙을 모르면 아래 같은 파일을 만들고 "분명히 라인을 추가했는데 왜 안 되지"로 몇 시간을 씁니다.

Before — 아래 라인이 영원히 무시되는 파일:

Config
# TYPE  DATABASE  USER  ADDRESS        METHOD
local   all       all                  peer
host    all       all   127.0.0.1/32   scram-sha-256
host    all       all   0.0.0.0/0      reject        # ← 여기서 모든 원격 접속이 종결됨
host    prod      app   10.0.3.0/24    scram-sha-256 # ← 도달 불가 (죽은 룰)

After — 구체적인 허용을 먼저, 포괄 거부를 마지막에:

Config
# TYPE     DATABASE  USER  ADDRESS        METHOD
local      all       all                  peer
host       all       all   127.0.0.1/32   scram-sha-256

# 변경1: 앱 서버 서브넷만 TLS 강제로 허용 (구체적 룰을 위로 이동)
hostssl    prod      app   10.0.3.0/24    scram-sha-256

# 변경2: 같은 대상의 평문 접속은 명시적으로 차단
hostnossl  prod      app   10.0.3.0/24    reject

# 변경3: 포괄 거부는 반드시 마지막 줄로 (기존 3번째 줄에서 이동)
host       all       all   0.0.0.0/0      reject

죽은 룰을 눈으로 확인하려면 pg_hba_file_rulesline_number 순서와 위 규칙을 대조하면 됩니다. 넓은 reject보다 아래에 있는 허용 라인은 전부 무효라고 보면 됩니다.

METHOD 의사결정표

METHOD보안 등급클라이언트 호환성권장 용도
trust없음 (무인증)전부운영 금지. 초기 부트스트랩 한정, 반드시 티켓화
peer중 (OS 계정 신뢰)local 전용서버 로컬 유지보수(postgres 계정)
identident 서버 필요레거시 내부망, 신규 도입 비권장
md5낮음 (레거시 해시)구형 JDBC/psycopg2 포함 전부구형 드라이버 호환 목적의 한시적 사용
scram-sha-256높음PG 10+ 서버, 최신 드라이버기본 권장값
cert매우 높음 (mTLS)클라이언트 인증서 배포 필요인터넷 경유·규제 환경

PG 14 분기: scram으로 바꿨는데 (d) 에러가 계속되는 경우

PostgreSQL 14부터 password_encryption 기본값이 scram-sha-256으로 바뀌었습니다. 문제는 기존 사용자 비밀번호는 여전히 md5 해시로 저장돼 있다는 점입니다. pg_hba만 scram-sha-256으로 바꾸면 저장된 해시와 인증 방식이 어긋나 password authentication failed가 납니다.

진단:

SQL
SELECT rolname, substring(rolpassword, 1, 4) AS hash_prefix
FROM pg_authid
WHERE rolcanlogin;

예상 출력:

CODE
 rolname  | hash_prefix
----------+-------------
 postgres | SCRA
 app      | md5          ← 이 줄이 원인

복구(비밀번호를 다시 설정해 재해싱):

SQL
SET password_encryption = 'scram-sha-256';
ALTER USER app WITH PASSWORD '새비밀번호';

확인 — hash_prefixSCRA로 바뀌었는지 재조회한 뒤 실제 접속 검증:

Bash
psql "host=10.0.3.10 user=app dbname=prod sslmode=require" -c 'select current_user'

SET은 세션 한정이므로, 앞으로 만들 계정에도 적용하려면 postgresql.confpassword_encryption을 확인하세요. 구형 JDBC(9.4.12 미만) 등 SCRAM 미지원 드라이버가 남아 있다면 드라이버 업그레이드가 정공법이고, md5는 어디까지나 임시 우회입니다.

버전별 차이

버전기본 해시pg_hba 관련 기능
9.6~13md5include 지시자 없음, pg_hba_file_rules는 10부터
14scram-sha-256으로 전환기존 md5 사용자 재해싱 필요
15·16·17scram-sha-256include·include_if_exists·include_dir, 정규식 매칭(/^app_.*) 지원

정규식 매칭 예시(PG 15+):

Config
hostssl  prod  "/^app_.*"  10.0.3.0/24  scram-sha-256

환경별 분기: Docker·Kubernetes·관리형 DB

환경소스 IP의 정체핵심 설정대표 함정
Docker브리지 네트워크의 컨테이너 IP(172.17.0.0/16 등)listen_addresses='*' + -p 5432:5432컨테이너 내부 127.0.0.1은 컨테이너 자신. POSTGRES_HOST_AUTH_METHOD=trust가 초기화 시 pg_hba를 통째로 덮어씀
KubernetesService ClusterIP가 아니라 Pod CIDRkubectl cluster-info dump | grep -i cidr로 확인 후 CIDR 기입사이드카/프록시 경유 시 소스 IP가 127.0.0.1로 바뀜
RDS / Cloud SQLVPC 내부 IPpg_hba 편집 불가 → 보안그룹·승인 네트워크 + rds.force_ssl=1 파라미터그룹pg_hba를 찾다 시간 낭비. 접근 통제는 SG가 대체

Docker에서 소스 IP 확인:

Bash
docker network inspect bridge --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{println}}{{end}}'

Kubernetes에서 Pod CIDR 확인:

Bash
kubectl cluster-info dump | grep -i -m2 'cluster-cidr'
# 예상: --cluster-cidr=10.244.0.0/16

확인된 대역을 그대로 pg_hba에 반영합니다.

Config
hostssl  prod  app  10.244.0.0/16  scram-sha-256

반영 절차: reload로 충분한 것 vs restart가 필요한 것

항목reloadrestart
pg_hba.conf 전체불필요
pg_ident.conf불필요
log_connections, log_min_duration_statement불필요
listen_addresses✅ 필요
port✅ 필요
max_connections✅ 필요
shared_buffers✅ 필요

reload 실행:

SQL
SELECT pg_reload_conf();
CODE
 pg_reload_conf
----------------
 t

또는 셸에서:

Bash
sudo -u postgres pg_ctl reload -D /var/lib/pgsql/16/data
# 또는
sudo systemctl reload postgresql

반영 확인은 두 가지를 함께 봅니다.

Bash
sudo tail -n 20 /var/log/postgresql/postgresql-16-main.log | grep -i sighup
# 예상: LOG:  received SIGHUP, reloading configuration files
SQL
SELECT line_number, address, auth_method FROM pg_hba_file_rules WHERE error IS NULL;

t가 반환됐는데 pg_hba_file_rules에 새 줄이 없다면 편집한 파일이 SHOW hba_file; 경로와 다른 것입니다.

고쳤는데도 안 될 때: 실패 분기 트리

분기 ① 나는 psql로 되는데 앱만 계속 실패한다

커넥션 풀이 예전 커넥션 또는 옛 설정을 붙들고 있는 경우입니다. HikariCP라면 maxLifetime(기본 30분)이 지나야 재생성됩니다.

YAML
spring:
  datasource:
    hikari:
      max-lifetime: 900000      # 15분
      keepalive-time: 300000

확진 방법은 단순합니다. 앱을 재기동해 즉시 성공하면 원인은 풀 캐시입니다. 서버 쪽에서는 실제 연결 주체를 확인하세요.

SQL
SELECT client_addr, usename, state, backend_start
FROM pg_stat_activity
WHERE datname = 'prod'
ORDER BY backend_start DESC LIMIT 10;

분기 ② pgbouncer를 경유한다

이 경우 진짜 관문은 pg_hba가 아니라 pgbouncer의 인증 설정입니다.

Bash
psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer -c 'SHOW CONFIG;' | grep -E 'auth_type|auth_file'
CODE
auth_type | scram-sha-256
auth_file | /etc/pgbouncer/userlist.txt

userlist.txt의 해시가 DB의 rolpassword와 어긋나면 pg_hba를 아무리 고쳐도 실패합니다. PG 14 이후 scram 전환 시 이 파일을 함께 갱신하지 않는 사고가 특히 잦습니다.

CODE
"app" "SCRAM-SHA-256$4096:...$...:..."

분기 ③ 서버 로그의 소스 IP가 낯설다

LB·NAT·서비스 메시 사이드카가 소스 IP를 치환한 상태입니다. 선택지는 둘입니다.

  • 로그에 찍힌 IP 대역을 그대로 CIDR에 반영한다(가장 빠름, 단 범위가 넓어질 수 있음).
  • 소스 IP 보존이 필요하면 프록시 계층에서 proxy protocol 또는 IP 보존 옵션을 검토한다.

이때 IP 기반 룰이 사실상 무력화되므로, 인증 강도(scram-sha-256 또는 cert)와 TLS 강제로 통제를 옮기는 편이 현실적입니다.

안전 원칙 — 급하다고 넘지 말아야 할 선

Config
# 절대 금지 조합
host  all  all  0.0.0.0/0  trust
  • trust + 0.0.0.0/0은 인증 없는 전면 개방입니다. 어떤 상황에서도 운영에 두지 않습니다.
  • CIDR는 최소 범위로: 가능하면 /32, 아니면 애플리케이션 서브넷 단위.
  • 평문 차단은 hostssl 허용 + hostnossl ... reject 조합으로 명시합니다.
  • 임시 완화 조치는 반드시 티켓으로 남기고 만료일을 지정하세요. 임시 trust 한 줄이 몇 년 남아 있는 경우가 실무에서 가장 자주 보고되는 사고 유형입니다.

공식 문서는 PostgreSQL 매뉴얼의 "Client Authentication" 장(pg_hba.conf File, Authentication Methods)과 pg_hba_file_rules 뷰 설명을 함께 확인하시면 됩니다.

결론: 접속 에러 3계층 체크리스트

에러 원문 키워드계층첫 명령
Connection refused ... 5432네트워크ss -lntp | grep 5432
no pg_hba.conf entry ... SSL off/onpg_hbaSELECT * FROM pg_hba_file_rules;
password authentication failed인증SELECT rolname, substring(rolpassword,1,4) FROM pg_authid;
Peer authentication failed인증(로컬 소켓)psql -h 127.0.0.1 ...로 재시도
too many clients already세션 슬롯별도 런북 참조

기억할 문장은 두 개입니다.

  1. pg_hba.conf를 열기 전에 ss -lntp부터.
  2. password authentication failed가 떴다면 pg_hba는 이미 통과한 것이다.

지금 바로 자기 서버에서 아래 두 줄을 실행해 잠재 오류를 점검해 보세요. 장애가 나기 전에 죽은 룰과 파싱 오류를 찾아내는 가장 값싼 방법입니다.

SQL
SHOW hba_file;
SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;

여기까지 통과했는데도 접속이 막힌다면 남은 후보는 커넥션 슬롯 고갈입니다. PostgreSQL too many clients already 30초 판정 복구 런북으로 이어서 확인하세요.

자주 묻는 질문 (FAQ)

Q1. no pg_hba.conf entry ... SSL off 에러가 났는데, 서버에서 SSL을 꺼야 하나요? 아닙니다. SSL off는 원인이 아니라 "이 접속이 평문이었다"는 기록입니다. 서버에 hostssl 라인만 있는 상황일 가능성이 높으므로, 클라이언트 접속 문자열에 sslmode=require를 추가하거나 서버에 적절한 host 라인을 추가하는 것이 정상 대응입니다.

Q2. pg_hba.conf를 고쳤는데 반영이 안 됩니다. 세 가지를 순서대로 확인하세요. ① SHOW hba_file;로 실제 적용 경로가 편집한 파일과 같은지, ② SELECT pg_reload_conf();t를 반환하는지, ③ SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;에 파싱 오류가 없는지. 참고로 listen_addressesport 변경은 reload가 아니라 restart가 필요합니다.

Q3. RDS나 Cloud SQL에서는 pg_hba.conf를 어디서 편집하나요? 관리형 DB는 pg_hba.conf를 직접 편집할 수 없습니다. 접근 제어는 보안그룹·승인된 네트워크가, TLS 강제는 파라미터 그룹의 rds.force_ssl=1 같은 설정이 대신합니다. 인증 강도는 password_encryption과 롤 비밀번호 재설정으로 관리하며, 세부 파라미터명은 각 클라우드 공식 문서 확인이 필요합니다.

✦ ✦ ✦
편집 검토 · Editorial Review

AI 도구는 자료 조사와 초안 작성의 보조 수단으로 사용될 수 있습니다. Nodelog는 공개 전 내용과 출처를 검토하고, 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서를 함께 확인하도록 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 ·
관련 공식 문서PostgreSQL 공식 문서

댓글

첫 번째 댓글을 남겨보세요.