TechFeedTechFeed
Backend

prepared statement, PgBouncer, Prisma | 풀러만 이미 있다고 나오면?

prepared statement s0 already exists는 6543 트랜잭션 풀러가 이름 있는 준비된 문장을 거절한 줄입니다. pgbouncer=true는 런타임 주소에만 두고 마이그레이션은 5432 직접 주소로 나눕니다. 연결 실패와 유니크 제약과 문장을 가릅니다. Prisma, Supabase, 백엔드, 한국 프리뷰. 2026년 9월 슈퍼베이스 문서.

by

prepared statement "s0" already exists는 표가 없어서가 아니라, 이름 있는 준비된 문장을 트랜잭션 풀러가 거절한 줄입니다. 6543 주소에는 pgbouncer=true를 붙이고, 마이그레이션은 5432 직접 주소로 빼세요.


로컬 5432는 조용한데 슈퍼베이스 풀러만 빨간 경우가 많습니다. 비밀번호를 다시 적어도 문장 이름이 풀러 뒤에서 부딪히면 그대로입니다.


슈퍼베이스는 2026-09-24 안내에서 수파바이저 트랜잭션 모드가 준비된 문장을 받지 않는다고 적습니다. 연결이 안 되는 오류, 풀에 자리가 없는 대기와는 문장이 다릅니다.


6543에서만 이미 있다고 나온다

직접 포트는 되는데, 풀러 포트만 이 문장입니다.


프리즈마는 쿼리를 준비된 문장으로 만들어 이름을 붙입니다. 포스트그레스는 그 이름을 세션(연결) 안에 둡니다. 트랜잭션 모드 풀러는 트랜잭션이 끝나면 서버 연결을 다른 클라이언트에게 넘깁니다. 다음 요청이 같은 이름 s0을 다시 만들면, 이전 세션의 문장이 아직 남아 already exists가 납니다. 포스트그레스 SQLSTATE는 42P05입니다.


로컬 포스트그레스나 슈퍼베이스 직접 연결(호스트 db, 포트 5432)은 풀러가 중간에 없어 이 충돌이 없습니다. 버셀처럼 함수가 짧게 붙었다 떨어지는 환경에서 6543을 쓰면 재현이 잘 됩니다. 한국에서 프리뷰만 가입이 실패하고 로컬은 초록인 자리가 여기인 경우가 있습니다.


데이터베이스 서버 랙. 풀러 포트에서만 준비된 문장이 충돌하는 상황을 떠올리게 하는 통로
직접 5432는 조용하고, 트랜잭션 풀러 6543에서만 준비된 문장 이름이 부딪힌다

세션 모드와 트랜잭션 모드

세션 모드는 준비된 문장을 견디고, 트랜잭션 모드는 기본으로 못 견딥니다.


연결준비된 문장프리즈마에서
직접 5432세션에 그대로 둠마이그레이션, 오래 켜 둔 서버
수파바이저 세션 모드지원한다고 슈퍼베이스가 안내연결 수가 풀 한도 안일 때
수파바이저 트랜잭션 6543지원하지 않음pgbouncer=true로 끄기
자체 피지바운서 1.21 미만트랜잭션 모드에서 이름 충돌pgbouncer=true
피지바운서 1.21 이상max_prepared_statements가 0보다 크면 풀러가 다룸그 값을 켠 뒤에 재시도

프리즈마 문서는 클라이언트가 피지바운서와 안정적으로 붙으려면 풀러가 트랜잭션 모드여야 한다고 적습니다. 그 모드에서 1.21.0 미만은 pgbouncer=true가 필요하고, 1.21.0부터는 max_prepared_statements를 0보다 크게 두면 준비된 문장을 풀러가 중계할 수 있다고 설명합니다. 슈퍼베이스가 호스팅하는 수파바이저 6543은 2026-09-24 안내대로 아직 준비된 문장을 받지 않으니, 그 주소는 끄는 쪽이 맞습니다. 유료 플랜의 전용 피지바운서는 프로젝트 설정에서 모드를 따로 확인하세요.


pgbouncer=true가 끄는 것

이 플래그는 풀 크기가 아니라 준비된 문장을 끕니다.


슈퍼베이스 프리즈마 트러블슈팅은 연결 문자열 끝에 pgbouncer=true를 붙이면 프리즈마가 준비된 문장을 만들지 않는다고 적습니다. 예시 호스트는 리전 풀러이고 포트는 6543입니다. 사용자 이름은 db사용자.프로젝트ref 형태인 풀러 계정을 그대로 씁니다. 비밀번호만 직접 연결과 같다고 사용자 이름을 짧은 쪽으로 바꾸면 이번 문장 전에 인증이 실패합니다.


자리 부족으로 기다리는 오류와는 약이 다릅니다. connection_limit을 올려도 이름 s0이 이미 있다는 문장은 남습니다. 반대로 플래그만 붙이고 함수마다 클라이언트를 새로 만들면 연결 수가 다시 터집니다. 한 프로세스에 클라이언트를 하나 두고, 6543에만 플래그를 다는 짝이 맞습니다.


앱은 6543, 플래그는 그 주소에만
# 런타임. 풀러 사용자 형식은 슈퍼베이스 화면의 문자열을 복사 DATABASE_URL="postgres://USER.PROJECT:PASSWORD@aws-0-REGION.pooler.supabase.com:6543/postgres?pgbouncer=true" # 마이그레이션. 직접 호스트, 포트 5432, pgbouncer 플래그 없음 DIRECT_URL="postgres://USER:PASSWORD@db.PROJECT.supabase.co:5432/postgres"

마이그레이션은 직접 주소로

migrate는 풀러 주소에 붙이면 같은 s0 문장을 냅니다.


프리즈마는 마이그레이션을 피지바운서 경유로 돌리면 prepared statement "s0" already exists가 날 수 있다고 적습니다. 스키마에 directUrl을 두고, 그 값만 직접 5432로 줍니다. 앱의 url은 풀러와 플래그를 유지합니다. 버셀 프리뷰에도 두 변수를 같이 넣어야, 빌드 중 migrate deploy가 풀러로 새지 않습니다.


직접 연결은 IPv6이거나, 프로젝트에 IPv4 추가 기능이 있어야 열릴 수 있습니다. 슈퍼베이스 풀링 문서는 직접 연결에 풀러 오버헤드가 없고, 서버리스의 짧은 연결에는 서버 쪽 풀러가 필요하다고 구분합니다. 오래 켜 둔 가상머신 하나면 앱 풀만으로 충분한 경우도 있습니다. 함수가 여러 개로 늘어나면 6543이 다시 필요합니다.


url과 directUrl을 나눈 스키마
datasource db { provider = "postgresql" url = env("DATABASE_URL") directUrl = env("DIRECT_URL") }
네트워크 스위치와 케이블. 앱 연결과 마이그레이션 연결을 포트로 나누는 장면
앱 쿼리는 플래그가 붙은 풀러로, 마이그레이션은 직접 포트로 나눈다

다른 클라이언트의 한 줄

라이브러리마다 끄는 스위치 이름만 다릅니다.


슈퍼베이스의 준비된 문장 끄기 안내를 그대로 옮기면 이렇습니다. 드리즐의 postgres.js는 prepare: false입니다. node-postgres는 쿼리 객체에 name을 넣지 않습니다. asyncpg는 statement_cache_size=0입니다. 프리즈마만 연결 주소의 pgbouncer=true입니다. 스택을 바꿔도 6543에 이름을 남기면 같은 42P05가 납니다.


알파인 이미지에서 쿼리 엔진 바이너리가 없는 오류, 유니크 제약 P2002, 호스트에 아예 못 가는 연결과는 로그 한 줄이 다릅니다. 엔진 파일이 없으면 쿼리 문장 전에 프로세스가 멈추고, 유니크는 행이 중복일 때입니다. 이번 문장은 연결은 열린 뒤, 준비된 문장 이름에서 멈춥니다.


플래그를 직접 주소에 붙이지 않기 | pgbouncer=true는 6543 런타임 주소에만 둡니다. 직접 주소까지 끄면 마이그레이션이 기대하는 준비된 문장 동작과 어긋날 수 있습니다. 두 환경 변수를 화면에서 한 번 더 읽으세요.


참고 자료


내부 연계: P2002 유니크, 알파인 쿼리 엔진, 연결 시간 초과


포트와 플래그는 2026년 9월 슈퍼베이스와 프리즈마 공개 문서 기준입니다. 대시보드에 적힌 문자열이 우선입니다.


자주 묻는 질문

로컬은 되는데 프리뷰만 실패해요.

로컬 주소가 5432 직접이고 프리뷰만 6543이면 이번 문장과 맞습니다. 프리뷰 환경 변수의 호스트와 포트를 읽고, 그 주소에만 pgbouncer=true가 있는지 확인하세요. 로컬에 플래그를 넣는 실험으로는 프리뷰가 고쳐지지 않습니다.


pgbouncer=true를 붙였는데 migrate가 또 죽어요.

마이그레이션이 아직 풀러 URL을 보고 있을 수 있습니다. directUrl을 5432 직접 호스트로 두고, 그 값에는 플래그를 넣지 마세요. 배포 로그에 찍힌 호스트가 pooler면 변수가 바뀐 것이 아닙니다.


connection_limit을 올리면 되나요?

그 값은 클라이언트가 여는 연결 수입니다. 이미 있는 준비된 문장 이름은 개수를 늘려도 남습니다. 풀 대기 문장이 따로 있을 때만 한도를 조정하세요.


세션 모드로 바꾸면 플래그가 필요 없나요?

슈퍼베이스는 직접 연결과 세션 모드가 준비된 문장을 지원한다고 적습니다. 트랜잭션 6543만 미지원입니다. 세션 모드는 연결을 더 오래 잡으므로, 함수 개수가 많은 프리뷰에서는 풀 한도를 먼저 보세요.


드리즐도 같은 문장이 나나요?

이름을 붙인 준비된 문장을 6543에 보내면 같은 42P05가 납니다. postgres.js는 prepare를 false로 둡니다. 프리즈마 플래그를 드리즐 쪽에 그대로 적어도 그 클라이언트는 읽지 않습니다.


P1001이랑 같이 보여요.

호스트에 TCP가 안 열리면 준비된 문장까지 가지 못합니다. 이미 있다는 문장은 연결이 성립한 뒤의 일입니다. 포트와 비밀번호가 맞은 다음에도 남는지 먼저 가르세요.


이 문장은 6543 트랜잭션 풀러와 이름 있는 준비된 문장이 만난 결과입니다. 런타임 주소에만 pgbouncer=true를 두고, 마이그레이션은 5432로 분리하면 됩니다. 관련 글: P2002, 알파인 엔진, 시간 초과.


prepared statementPgBouncerPrisma슈퍼베이스6543pgbouncer마이그레이션백엔드풀러개발자

함께 보면 좋은 문제 해결

EXPLORE / Backend

이어서 읽어보기

전체 토픽 둘러보기 →