PostgreSQL 14에서 17로 마이그레이션하기 전 필수 체크리스트
pg_upgrade · Logical Replication · Breaking Changes 실무 사례
2026년 11월이면 PostgreSQL 14가 EOL을 맞는다. 아직 다섯 달이 남았고 "나중에 해도 되지" 싶겠지만, 대규모 데이터베이스 마이그레이션은 "언제 할지" 결정하는 것보다 "어떻게 할지" 준비하는 데 시간이 훨씬 더 걸립니다. 저도 처음 메이저 업그레이드를 맡았을 때 '그냥 apt upgrade 아닌가?' 싶었는데, 실제로 해보니 전혀 다른 이야기였습니다.
14→17은 세 개의 메이저 버전(15, 16, 17)을 한 번에 건너뛰는 업그레이드입니다. 각 버전에서 누적된 Breaking Changes, 제거된 기능, SQL 동작 변경이 모두 한꺼번에 밀려오는데, 그 누적된 변경을 한 번에 맞닥뜨렸을 때 며칠 치 삽질을 막아준 게 바로 체크리스트였습니다. 이 글에서는 어떤 방법을 선택하든 공통으로 확인해야 할 사전 점검 항목부터, 다운타임 최소화 전략까지 실제로 써먹을 수 있는 체크리스트를 중심으로 풀어봅니다.
운영 중인 PostgreSQL 14 데이터베이스가 있고, 업그레이드 담당자가 본인이라면 이 글이 도움이 될 것입니다. 특히 search_path 설정을 직접 다루거나, 익스텐션을 사용 중이거나, 모니터링 대시보드가 있다면 이 글에서 다루는 변경사항이 본인 코드와 운영에 직접 영향을 줄 수 있습니다.
핵심 개념
PostgreSQL 메이저 업그레이드가 일반 패키지 업데이트와 다른 이유
PostgreSQL 메이저 버전 업그레이드는 단순 바이너리 교체가 아닙니다. 데이터 디렉토리의 내부 포맷 자체가 버전마다 달라지기 때문에, 기존 데이터를 새 형식에 맞게 변환하는 과정이 반드시 필요합니다.
데이터 디렉토리(PGDATA): PostgreSQL이 테이블, 인덱스, 트랜잭션 로그 등 모든 데이터를 저장하는 파일 시스템 경로. 메이저 업그레이드 시 이 디렉토리 구조 자체가 변경되기 때문에 단순 패키지 업데이트로는 기존 데이터를 읽을 수 없습니다.
WAL(Write-Ahead Log): 데이터베이스 변경사항을 실제 테이블에 반영하기 전 먼저 기록하는 트랜잭션 로그. 장애 복구와 복제의 핵심이며, PGDATA 디렉토리 내
pg_wal폴더에 저장됩니다.
마이그레이션 방법은 크게 세 가지이며, 서비스 규모와 허용 다운타임에 따라 선택이 달라집니다.
| 방법 | 다운타임 | 특징 |
|---|---|---|
pg_dumpall / pg_restore |
길다 (DB 크기 비례) | 가장 단순·안전, 소규모 DB에 적합 |
pg_upgrade |
짧다 (분 단위) | In-place 업그레이드, --link 모드로 수 분 내 완료 |
| Logical Replication | 거의 없음 (초 단위) | 프로덕션 무중단이 필요할 때 권장, 복잡도 높음 |
14→17 사이에 쌓인 Breaking Changes 한눈에 보기
세 버전을 건너뛰는 만큼, 각 버전에서 생긴 변경이 모두 영향을 줍니다. 실무에서 자주 맞닥뜨리는 상황인데, 버전별로 정리해두면 사전 점검이 훨씬 수월합니다.
| 버전 | 주요 변경 |
|---|---|
| PG15 | GRANT ALL 시 public 스키마 기본 권한 제거; MERGE 문 신규 도입; window function 내 DISTINCT 지원 |
| PG16 | scram-sha-256가 기본 인증 방식으로 변경 (오래된 클라이언트 드라이버 호환성 주의); GENERATED 컬럼의 상속·파티션 제약 강화; pg_stat_io 뷰 추가; search_path 보안 강화 |
| PG17 | db_user_namespace 제거; old_snapshot_threshold 제거; adminpack 코어에서 완전 제거; 함수의 safe search_path 강제 적용 |
PG16의 scram-sha-256 기본 인증 방식 전환은 특히 주의가 필요합니다. 오래된 JDBC 드라이버나 클라이언트 라이브러리를 사용하고 있다면 업그레이드 후 인증 오류가 발생할 수 있으니, 드라이버 버전도 함께 점검해두면 좋습니다.
PG17에서 특히 주목할 변화
PG17은 Logical Replication 업그레이드 지원을 크게 강화했습니다. 기존에는 pg_upgrade를 실행하면 논리 복제 슬롯이 사라져서 업그레이드 후에 구독을 처음부터 다시 설정해야 했는데, PG17부터는 publisher가 PG17인 경우에 한해 논리 복제 슬롯과 subscriber의 구독 상태가 보존됩니다. publisher가 PG16 이하라면 여전히 슬롯이 보존되지 않으므로, 복제 구성이 있다면 publisher 버전을 먼저 확인해두는 것이 좋습니다.
논리 복제 슬롯(Logical Replication Slot): 특정 subscriber가 어디까지 WAL을 소비했는지 추적하는 서버 측 포인터. 슬롯이 사라지면 처음부터 전체 재동기화(resync)가 필요합니다.
실전 적용
사전 점검: 업그레이드 전 반드시 실행해봐야 할 쿼리들
어떤 방법을 선택하든, 아래 쿼리들은 먼저 실행해보시길 권합니다. 저도 처음엔 헷갈렸는데, --check 옵션만 믿다가 런타임에서야 search_path 문제가 터진 경험이 있어서요. 공식 문서에 잘 나오지 않는 내용인데, 경험상 이 쿼리들이 제일 먼저 문제를 잡아줍니다.
-- 1. 현재 버전 및 설치된 익스텐션 목록 확인
SELECT version();
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE installed_version IS NOT NULL;
-- 2. PG17에서 제거된 설정값 확인
SHOW db_user_namespace; -- PG17에서 제거됨
SHOW old_snapshot_threshold; -- PG17에서 제거됨
-- 3. search_path가 명시되지 않은 사용자 정의 함수 검색
-- 표현식 인덱스·Materialized View에서 이런 함수를 쓰면 업그레이드 후 쿼리 실패 가능
SELECT proname, pronamespace::regnamespace
FROM pg_proc
WHERE prokind = 'f'
AND pronamespace NOT IN (
SELECT oid FROM pg_namespace
WHERE nspname LIKE 'pg_%' OR nspname = 'information_schema'
)
AND NOT (proconfig @> ARRAY['search_path=pg_catalog']);
-- 4. pg_stat_bgwriter 컬럼 목록 확인
-- buffers_backend_fsync가 PG17에서 제거됨 — 모니터링 쿼리에서 참조 중이라면 업데이트 필요
SELECT attname
FROM pg_attribute
WHERE attrelid = 'pg_stat_bgwriter'::regclass
AND attnum > 0
AND NOT attisdropped;PG17에서 익스텐션 상황은 성격이 다른 세 가지로 나뉩니다. 같은 "문제 있음" 으로 묶으면 혼란이 생기니 구분해두시면 좋습니다.
| 익스텐션 | 상태 |
|---|---|
adminpack |
PG17 코어에서 완전 제거 — 업그레이드 전 DROP EXTENSION 필요 |
age (Apache AGE) |
PG17 호환성 아직 불완전 — 공식 호환 릴리즈 전 사용 시 주의 |
hll, pgrouting |
PG17 호환 버전 커뮤니티에서 정상 배포 중 — 버전 업데이트 후 사용 가능 |
pg_upgrade를 이용한 In-place 업그레이드
다운타임이 수십 분 정도 허용되는 환경이라면 pg_upgrade가 가장 현실적인 선택입니다. --link 모드를 쓰면 파일을 복사하지 않고 하드링크로 연결하기 때문에 속도가 크게 빨라집니다. 다만, 하드링크 특성상 실패 시 구 클러스터 파일이 손상될 수 있으니 전체 백업은 반드시 먼저 해두시길 권합니다.
# 1. PG17 바이너리 설치 (기존 PG14 클러스터는 그대로 유지)
sudo apt install postgresql-17
# 2. 드라이런: 실제 변경 없이 호환성만 점검
/usr/lib/postgresql/17/bin/pg_upgrade \
--old-datadir /var/lib/postgresql/14/main \
--new-datadir /var/lib/postgresql/17/main \
--old-bindir /usr/lib/postgresql/14/bin \
--new-bindir /usr/lib/postgresql/17/bin \
--check
# 3. 실제 업그레이드 (--link: 하드링크로 수 분 내 완료)
# --jobs는 서버 CPU 코어 수에 맞게 조정할 것 (2코어 서버라면 --jobs=2)
/usr/lib/postgresql/17/bin/pg_upgrade \
--old-datadir /var/lib/postgresql/14/main \
--new-datadir /var/lib/postgresql/17/main \
--old-bindir /usr/lib/postgresql/14/bin \
--new-bindir /usr/lib/postgresql/17/bin \
--link \
--jobs=8
# 4. 업그레이드 직후 통계 재수집 (필수 — 생략하면 쿼리 플랜이 망가질 수 있음)
./analyze_new_cluster.sh
# 5. 충분히 검증한 뒤 구 클러스터 정리
./delete_old_cluster.sh--check 단계에서 오류가 없더라도 런타임에서 search_path 관련 문제가 나올 수 있습니다. 스테이징 환경에서 한 번 전체 플로우를 돌려보는 것을 강력히 권합니다.
--link모드(하드링크 업그레이드): 파일을 복사하지 않고 기존 PG14 데이터 파일을 PG17 디렉토리에 하드링크로 연결하는 방식. 대용량 DB에서 업그레이드 시간을 수 분으로 단축시켜주지만, 원본과 링크가 같은 inode를 공유하기 때문에 업그레이드 중 문제가 생기면 구 클러스터도 영향을 받습니다.
Logical Replication 기반 무중단 업그레이드
프로덕션 환경에서 다운타임이 거의 허용되지 않는다면, 신규 PG17 서버를 띄우고 논리 복제로 데이터를 동기화한 뒤 앱 연결을 전환하는 방식이 현실적입니다.
[PG14 Primary]
│
│ 논리 복제 (Logical Replication)
▼
[PG17 신규 서버] ← 복제 동기화 완료 후
│
│ 앱 연결 전환 (수 초 다운타임)
│ PG14 중단
▼
[PG17 Primary]이 과정을 직접 구성하기 복잡하다면 pg_easy_replicate 같은 오픈소스 CLI 도구를 활용해볼 수 있습니다. 저희 팀이 실제로 사용해봤는데, 슬롯과 구독 설정 자체는 명령 몇 줄로 정말 편하게 처리됐습니다. 다만 초기 복제 진행률을 실시간으로 모니터링하는 기능이 아쉬웠고, 대용량 테이블이 있을 때는 진행 상황을 직접 pg_replication_slots로 확인해야 했습니다. AWS RDS 환경이라면 Blue/Green 배포 기능이 같은 역할을 해줍니다.
pg_easy_replicate: Logical Replication 기반 무중단 업그레이드를 CLI 명령 몇 줄로 처리할 수 있게 추상화한 오픈소스 도구. 복잡한 슬롯·구독 관리를 자동화해줍니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| PG17 성능 개선 | 쿼리 플래너 개선, I/O 처리 효율화(pg_stat_io)로 업그레이드 자체가 성능 향상 효과를 가져옴 |
| Logical Replication 안정성 | PG17부터 pg_upgrade 시 복제 슬롯 보존 (publisher가 PG17인 경우) — 재동기화 없이 복제 이어가기 가능 |
| 보안 강화 | search_path 보안 강화, safe search_path 강제 적용으로 스키마 인젝션 위험 감소 |
| 관리형 서비스 지원 | AWS RDS, Azure Flexible Server, Google Cloud SQL 모두 14→17 인플레이스 업그레이드 경로 공식 지원 |
| EOL 대응 | 2026년 11월 PG14 EOL 이전 완료 시 보안 패치 및 커뮤니티 지원 지속 수혜 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
search_path 문제 |
표현식 인덱스·Materialized View에서 비기본 스키마 참조 함수가 있으면 업그레이드 후 쿼리 실패 | 함수 정의에 SET search_path = schema_name 명시 |
| 익스텐션 호환성 | postgis 계열 사용 시 search_path 서버 파라미터에 "$user", public, postgis 추가 필요 |
업그레이드 전 익스텐션 목록 전수 검토 |
| 통계 정보 미이전 | pg_upgrade는 옵티마이저 통계를 이전하지 않음 — 미실행 시 쿼리 플랜 열화 |
업그레이드 직후 analyze_new_cluster.sh 실행 |
--link 모드 위험 |
하드링크 방식이므로 실패 시 구 클러스터 파일 손상 가능 | --link 사용 전 전체 백업 필수 |
| 모니터링 쿼리 영향 | pg_stat_bgwriter.buffers_backend_fsync 컬럼이 PG17에서 제거됨 |
Grafana/Prometheus 대시보드 업데이트 |
| 복제 슬롯 재생성 | publisher가 PG17 미만인 상태에서 pg_upgrade 시 논리 복제 슬롯 보존 불가 |
마이그레이션 전략에 따라 슬롯 재생성 계획 수립 |
| 드라이버 호환성 | PG16부터 scram-sha-256이 기본 인증 방식 — 오래된 클라이언트 라이브러리에서 인증 오류 가능 |
클라이언트 드라이버 버전 사전 확인 및 업데이트 |
실무에서 가장 흔한 실수
-
--check만 통과하면 끝이라고 생각하는 것 —pg_upgrade --check는 데이터 디렉토리 구조 호환성만 검사합니다.search_path관련 함수 동작 오류나pg_stat_bgwriter컬럼 제거로 인한 모니터링 쿼리 실패는 런타임에 가서야 드러납니다. 공식 문서에는 잘 나오지 않는 내용인데, 실제로 겪어보면 제일 당황스러운 부분입니다. -
analyze_new_cluster.sh실행을 잊거나 나중으로 미루는 것 — 업그레이드 직후에는 통계 정보가 없어서 옵티마이저가 엉뚱한 인덱스 스캔을 선택할 수 있습니다. 트래픽이 몰리기 전에 미리 실행해두면 좋습니다. -
익스텐션 호환성을 익스텐션 버전만으로 확인하는 것 —
postgis같은 익스텐션은 버전이 맞더라도search_path서버 파라미터 설정이 함께 바뀌지 않으면 함수 해석 오류가 발생합니다. 익스텐션 릴리즈 노트와 함께 서버 파라미터 변경 이력도 같이 확인해두면 좋습니다.
마치며
PostgreSQL 14→17 마이그레이션에서 가장 큰 리스크는 버전 차이 자체가 아니라, 사전 점검 없이 넘어가는 search_path 문제와 익스텐션 호환성입니다. 도구는 충분히 성숙해 있고, 관리형 서비스라면 콘솔 몇 번으로 업그레이드가 가능한 시대가 됐습니다. 이 체크리스트를 미리 챙겨두면, 프로덕션 업그레이드 당일 새벽 두 시에 롤백을 고민하는 상황은 충분히 피할 수 있습니다.
지금 바로 시작해볼 수 있는 3단계:
-
설치된 익스텐션 목록부터 뽑아보시면 좋습니다.
SELECT name, installed_version FROM pg_available_extensions WHERE installed_version IS NOT NULL;을 실행해adminpack,age등 PG17에서 제거되거나 호환성이 불완전한 항목이 있는지 확인할 수 있습니다. -
스테이징 환경에서
pg_upgrade --check를 먼저 돌려보시면 좋습니다. 프로덕션을 건드리기 전에 드라이런을 돌려보면 호환성 문제를 미리 발견할 수 있습니다. 위에서 소개한search_path점검 쿼리도 함께 실행해두면 런타임 오류를 크게 줄일 수 있습니다. -
모니터링 대시보드에서
pg_stat_bgwriter.buffers_backend_fsync를 참조하는 쿼리가 있다면 지금 미리 수정해두는 것이 좋습니다. Grafana나 Prometheus에서 이 컬럼을 쓰고 있다면 PG17 업그레이드 후 대시보드가 에러를 내뱉을 수 있습니다. 업그레이드 당일 대시보드 오류까지 함께 잡아두면 혼란을 크게 줄일 수 있습니다.
참고 자료
- PostgreSQL 공식 문서: pg_upgrade
- PostgreSQL 공식 문서: 클러스터 업그레이드 가이드
- PostgreSQL 17 릴리즈 노트 (공식)
- PostgreSQL 17 출시 공식 발표
- GitHub: PostgreSQL 14→17 업그레이드 가이드 | alimoradimllm
- Data Egret: PostgreSQL 메이저 업그레이드 Ultimate Guide (2026)
- Techbuddies: pg_upgrade 7가지 Best Practices
- pgEdge: Zero Downtime Major Version Postgres Upgrades
- pganalyze: Zero downtime Postgres upgrades with logical replication
- AWS RDS: PostgreSQL 메이저 버전 업그레이드 가이드
- Azure: PostgreSQL 메이저 버전 업그레이드 개념
- PostgreSQL Logical Replication 업그레이드 공식 문서