Prisma P1001, 데이터베이스 연결, Can't reach database | 로컬은 되고 프리뷰만 끊기면?
프리즈마 P1001은 쿼리가 틀린 게 아니라 호스트와 포트까지 TCP가 안 열린 줄입니다. 로컬 .env 초록과 버셀 프리뷰 환경 변수는 다른 칸이고, 슈퍼베이스 풀러 6543과 직접 주소, 일시정지 프로젝트를 먼저 봅니다. Prisma, DATABASE_URL, 슈퍼베이스, 버셀, Next.js, 카카오 로그인 콜백, 1인 개발자 기준. 2026년 9월 프리즈마·슈퍼베이스 공식 문서.
P1001은 쿼리가 틀린 게 아니라, 프리즈마가 적힌 호스트와 포트까지 TCP로 한 번도 못 붙은 줄입니다. 로컬이 초록이어도 버셀 프리뷰 환경 변수에 같은 주소가 없으면 그 칸에서 끊깁니다.
넥스트로 카카오 로그인을 붙이다가 콜백이 500으로 떨어질 때가 있습니다. 콘솔 주소는 맞는데 서버 로그에 Can't reach database server가 찍혀 있으면, 카카오가 아니라 디비 칸입니다. 슈퍼베이스 무료 프로젝트가 멈춰 있거나, 풀러 포트와 직접 포트를 바꿔 넣었을 때도 같은 코드가 납니다.
제가 반복한 순서는 메시지에 찍힌 호스트부터 읽고, 풀러와 직접 주소를 갈라 넣고, 프리뷰에 로컬 값이 남았는지 보는 것입니다. 근거는 프리즈마 오류 코드와 슈퍼베이스 프리즈마 안내에 둡니다.
P1001은 쿼리 오류가 아니다
호스트와 포트까지 소켓이 안 열린 줄입니다. 프리즈마 문서의 P1001 문장은 Can't reach database server at {database_host}:{database_port}입니다. 클라이언트가 기동하거나 첫 쿼리를 보내는 순간에, 적힌 주소로 TCP가 성립하지 않으면 이 코드가 납니다.
표가 있는지, 유니크가 겹쳤는지는 아직 볼 자리가 아닙니다. 그 검사는 연결이 열린 뒤에야 합니다. 그래서 스키마를 고치고 generate만 다시 돌려도 P1001은 그대로입니다. 엔진이 서버에 손을 못 댔으니까요.
로컬 npm run dev가 초록인 것과도 별개입니다. 개발 서버는 .env의 주소를 읽고, 버셀 프리뷰는 대시보드에 넣은 값을 읽습니다. 두 칸이 다르면 한쪽만 끊깁니다. 제가 사이드 프로젝트를 올릴 때 가장 자주 본 장면이 바로 이 갈림입니다.
먼저 읽을 것 | 메시지에 찍힌 호스트와 포트를 그대로 적어두세요. 비밀번호는 로그에 남기지 않습니다. 그 두 칸이 슈퍼베이스 연결 화면의 풀러인지 직접 주소인지만 맞춰도 절반은 끝납니다.
P1001은 쿼리 전, 호스트와 포트까지 소켓이 안 열린 줄이다
P1000, P1002, P2021과 어디서 갈리나
인증 실패는 P1000, 시간 초과는 P1002, 표 없음은 P2021입니다. 네 줄이 콘솔에 비슷하게 보여도 고치는 칸이 다릅니다. 프리즈마 오류 코드 문서가 호스트·자격 증명·타임아웃·스키마를 나눠 적습니다.
코드
뜻
먼저 볼 칸
P1001
호스트:포트에 TCP가 안 열림
주소, 포트, 일시정지, 방화벽
P1000
서버는 보였는데 자격 증명이 거절됨
사용자, 비밀번호, 역할
P1002
닿았는데 시간 안에 악수를 못 마침
connect_timeout, 부하
P2021
연결은 됐는데 표가 없음
migrate deploy
ECONNREFUSED
그 주소의 프로세스가 거절함
도커 localhost, 서비스 이름
컨테이너 안에서 localhost:5432가 거절되면 노드의 ECONNREFUSED가 먼저 보이기도 합니다. 그 줄은 호스트가 아니라 그 컨테이너를 가리킵니다. 프리즈마는 같은 실패를 P1001로 감싸 보여 줄 수 있어요. 도커 칸과 클라우드 호스트 칸을 한 글에서 섞지 마세요.
표가 없다는 P2021은 연결이 이미 된 뒤의 일입니다. 프리뷰 디비가 비어 있으면 마이그레이션을 넣어야지, 연결 문자열을 더 길게 만들어도 표는 안 생깁니다.
로컬은 되고 프리뷰만 끊기는 이유
프리뷰는 로컬 .env를 안 읽고, 대시보드 값을 씁니다. 버셀 환경 변수 문서도 Production, Preview, Development를 따로 둡니다. 로컬에만 넣으면 프리뷰 함수는 빈 문자열이거나 예전 값을 들고 기동합니다.
슈퍼베이스 무료 칸은 한동안 쿼리가 없으면 프로젝트를 멈춥니다. 멈춘 호스트는 포트가 살아 있어도 받지 않아서 P1001로 떨어집니다. 대시보드에서 프로젝트를 다시 켠 다음, 같은 주소로 한 번 더 붙으면 그 줄은 사라지는 경우가 많습니다.
직접 주소 db.{프로젝트}.supabase.co는 IPv6만 열리는 경우가 있습니다. 집 회선이나 일부 CI는 IPv4만 나가서, 로컬에선 되고 깃허브 액션만 끊기기도 합니다. 풀러 호스트는 IPv4로 받는 칸이라, 클라이언트 주소는 풀러로 두는 편이 안전합니다.
이 한 줄은 프로토콜, 호스트, 포트만 보여 줍니다. 비밀번호는 URL 객체 밖으로 안 꺼냅니다. 프리뷰 로그에 연결 문자열 전체를 찍으면 시크릿이 남으니, 호스트 세 칸만 대조하세요.
버셀에 값을 넣었다면 Preview 환경에 체크가 됐는지도 봅니다. Production만 켜 두면 메인 배포는 되고 풀 리퀘스트 프리뷰만 P1001이 납니다. 반대로 로컬 .env에 풀러를 넣고 프리뷰에 직접 주소를 넣으면, 마이그레이션과 런타임이 서로 다른 칸을 때립니다.
슈퍼베이스 풀러와 직접 주소를 섞으면
클라이언트는 6543, 마이그레이션은 직접 주소입니다. 슈퍼베이스 연결 화면은 트랜잭션 풀러(보통 6543)와 세션 풀러, 직접 연결을 나눠 보여 줍니다. 프리즈마 클라이언트는 서버리스에서 연결을 자주 여니 풀러를 쓰고, migrate는 준비된 문을 쓰므로 직접 주소가 필요합니다.
칸
포트
쓰는 곳
트랜잭션 풀러
6543
런타임 DATABASE_URL, pgbouncer=true
세션 풀러
5432 (풀러 호스트)
긴 세션, 일부 마이그레이션
직접 연결
5432 (db 호스트)
DIRECT_URL, migrate
6543에 풀러 옵션을 안 붙이면 준비된 문 오류가 따로 납니다. 그건 P1001이 아닙니다. 반대로 직접 호스트에 6543을 붙이거나, 풀러 호스트에 스키마 없는 경로를 넣으면 소켓부터 실패해 P1001이 납니다. 연결 화면에서 복사한 문자열을 칸마다 그대로 쓰는 편이 안전합니다.
슈퍼베이스 안내는 닿기 전에 시간이 끝나면 connect_timeout=30을 붙이라고 합니다. 타임아웃을 늘려도 호스트가 잘못됐으면 P1001은 남습니다. 초만 키우기 전에 메시지에 찍힌 호스트가 연결 화면과 같은지부터 보세요.
메시지에 찍힌 호스트부터 읽고, 비밀번호는 로그에 남기지 않습니다. 순서를 정해 두면 스키마와 마이그레이션을 먼저 의심하는 시간을 줄입니다.
[ ] 로그의 호스트:포트가 슈퍼베이스 연결 화면과 같은가
[ ] 프로젝트가 일시정지 상태가 아닌가
[ ] 프리뷰 환경에 DATABASE_URL, DIRECT_URL이 들어 있는가
[ ] 런타임은 6543 풀러, migrate는 직접 주소인가
[ ] 비밀번호 특수문자를 URL 인코딩했는가
[ ] 로컬 도커라면 localhost가 그 컨테이너를 가리키지 않는가
npx prisma validate는 스키마 문법만 봅니다. 연결을 시험하지 않아요. 문법 초록을 보고 주소가 맞다고 생각하면 P1001 앞에서 한 바퀴 돕니다. 실제 악수는 첫 쿼리나 $connect()에서 일어납니다.
스키마 문법과 실제 악수는 다른 명령
npx prisma validate
npx prisma db pull --print
db pull --print는 원격 스키마를 읽어 옵니다. 여기서 P1001이 나면 앱 코드가 아니라 주소 칸입니다. 성공하면 표 목록이 나오고, 그때부터는 P2021 같은 스키마 칸을 보면 됩니다.
비밀번호에 @나 #가 있으면 URL이 호스트를 잘라 먹습니다. 연결 화면에서 복사한 값을 쓰지 않고 손으로 이어 붙일 때 자주 납니다. 호스트가 이상하게 잘렸다면 인코딩부터 고치세요. 포스트그레스 listen_addresses가 로컬만 열려 있는 자체 서버도, 바깥에서 보면 같은 P1001입니다.
메시지에 찍힌 호스트와 연결 화면을 한 줄로 대조한다
카카오 콜백 500 뒤에 숨은 경우
콜백 주소가 맞아도 사용자 행을 못 쓰면 500입니다. 카카오 콘솔의 리다이렉트 URI가 통과해도, 콜백 라우트가 프리즈마로 사용자를 찾다가 P1001을 만나면 화면은 그냥 500입니다. KOE006이 아닌데 로그인이 실패하면 디비 줄을 펼치세요.
토스 웹훅도 비슷합니다. 10초 안에 200을 못 주면 재시도가 붙는데, 그 앞에 디비가 안 열리면 결제 칸이 아니라 연결 칸입니다. 웹훅 서명 검증보다 P1001이 먼저면, 서명 코드를 고칠 자리가 아닙니다.
제가 쓰는 기준은 짧습니다. 콜백 로그에 카카오 오류 코드가 있으면 콘솔 주소, 프리즈마 P1001이 있으면 호스트와 환경 변수. 두 줄을 한 문장으로 고치지 않습니다.
섞지 말 것 | 표가 없다는 P2021, 유니크가 겹친 P2002, 컨테이너 localhost 거절은 각각 다른 글의 칸입니다. P1001은 그 전에 소켓이 안 열린 줄만 봅니다.
출처
숫자와 코드 이름은 공식 문서의 문장을 따릅니다. 연결 화면의 호스트는 프로젝트마다 다르니, 아래에 적힌 URL에서 지금 값을 복사하세요.
프리뷰는 .env를 안 가져갑니다. 대시보드 Preview 환경에 DATABASE_URL과 DIRECT_URL이 들어 있는지 보세요. Production만 켜 두면 풀 리퀘스트 프리뷰는 빈 값으로 기동합니다.
슈퍼베이스를 어제까지 썼는데 오늘 갑자기 끊기면?
무료 프로젝트가 일시정지됐는지 대시보드를 먼저 엽니다. 멈춰 있으면 호스트가 살아 보여도 받지 않아 P1001이 납니다. 다시 켠 뒤 같은 주소로 한 번 더 붙이세요.
connect_timeout을 늘리면 해결되나요?
부하로 악수가 늦을 때는 도움이 됩니다. 호스트가 잘못됐거나 프로젝트가 멈춰 있으면 초만 키워도 같은 코드가 납니다. 메시지에 찍힌 호스트를 연결 화면과 맞춘 뒤에 초를 손보세요.
도커 컴포즈에서 5432가 거절되면 P1001인가요?
노드에는 ECONNREFUSED로 보이거나 프리즈마가 P1001로 감쌀 수 있습니다. 그 경우 localhost는 컨테이너 자신입니다. 같은 컴포즈면 서비스 이름과 컨테이너 포트를 쓰고, 호스트 디비는 host.docker.internal을 봅니다.
카카오 로그인이 500인데 콘솔 주소는 맞습니다.
콜백 라우트가 사용자를 찾다가 디비에 못 붙으면 화면은 500입니다. 서버 로그에 P1001이 있으면 리다이렉트 URI가 아니라 연결 문자열입니다. KOE006과 그 줄을 한 원인으로 묶지 마세요.
prisma validate가 초록이면 주소는 맞은 건가요?
아닙니다. validate는 스키마 문법만 봅니다. 실제 악수는 첫 쿼리나 db pull에서 일어납니다. 문법 초록과 P1001은 같이 있을 수 있습니다.
P1001은 적힌 호스트와 포트까지 소켓이 열렸는가만 보면 됩니다. 메시지에 찍힌 주소를 연결 화면과 맞추고, 프리뷰 환경 변수와 일시정지를 확인하면 대부분 풀립니다. 표가 없거나 유니크가 겹친 줄은 연결이 열린 다음입니다. 관련 글: P2021 테이블 없음, P2002 유니크, 도커 localhost 거절, ETIMEDOUT.