Postgres는 30년 동안 쿼리 취소를 대담하게 처리해 왔습니다.
Specific.dev는 코딩 에이전트를 위해 구축된 클라우드 플랫폼이며, 데이터베이스 계층은 Neon으로 구동됩니다. 사례 연구 읽기 








제품
솔루션
리소스
코어 데이터베이스
기본 제공 기능
Neon Serverless Postgres란 무엇인가, Databricks 제공
사용 사례
구축 및 운영
학습
회사
Postgres는 30년 동안 쿼리 취소를 대담하게 처리해 왔습니다

George MacKerron–소프트웨어 개발자
2026년 3월 5일
최신 업데이트만 받아보세요. 스팸은 없습니다.
구독하기
Postgres 쿼리에 브레이크를 걸어야 하는 이유는 몇 가지가 있습니다. 완료까지 너무 오래 걸리고 있을 수도 있습니다. 속도를 몇 자릿수나 더 빠르게 만들어 줄 인덱스를 만드는 걸 깜빡했다는 사실을 뒤늦게 깨달았을 수도 있습니다. 혹은 어떤 이유로든 결과가 더 이상 필요하지 않을 수도 있습니다.
아니면 당신이나 당신의 LLM 동료가 SQL에서 실수를 했고, 응답을 기다리는 동안에야 그 사실을 알아차렸을 수도 있습니다. 어쩌면 그 실수가 [무서운 코드 진행 재생] 귀중한 프로덕션 데이터를 연쇄 피해로 만들 수도 있는 종류일지도 모릅니다. 하지만 그렇지 않기를 바랍니다. 아니면, 정말 그렇더라도 Neon처럼 타임 트래블을 지원하는 시스템을 쓰고 있기를 바랍니다.
이유가 무엇이든, psql 명령줄 사용자라면 Ctrl-C는 이미 손에 밴 동작입니다. 그러면 이제 화면에는 Cancel request sent라는 문구가 보이고, 잠시 뒤에는 사실상 오류라고 하기도 애매한 ERROR: cancelling statement due to user request 메시지가 따라옵니다. 그런데 그 뒤에서는 실제로 무슨 일이 벌어지고 있을까요?
Postgres 쿼리를 취소하려면, Postgres 클라이언트는 서버에 CancelRequest 형태의 새롭고 추가적인 연결을 만듭니다. 서버는 시작 메시지의 맨 앞에 있는 마법 같은 프로토콜 버전 번호를 통해 이것이 일반적인 클라이언트 연결과 다르다는 점을 구분합니다. 최신 Postgres 프로토콜은 v3.2, 즉 0x00030002이지만, CancelRequest는 자신을 v1234.5678, 즉 0x04d2162e이라고 주장합니다.
CancelRequest는 특정 쿼리가 아니라 연결을 대상으로 합니다. 대상 연결은 서버가 원래 연결 핸드셰이크의 마지막에 클라이언트에게 제공했던 두 개의 숫자로 서버에 식별됩니다(BackendKeyData 메시지를 통해 전달됨).
그 숫자는 4바이트 프로세스 ID와 비밀 랜덤 키 값이며, 전통적으로 이 키 역시 길이가 4바이트입니다. 메시지의 초기 길이 값을 제외하면, 이것이 클라이언트가 보내는 전부입니다. 이 4바이트 비밀 키 외에는 어떤 자격 증명도 필요하지 않습니다.
Postgres가 쿼리가 아니라 연결 기준으로 취소한다는 점은 어쩌면 약간 의외일 수 있습니다. 이 때문에 경쟁 상태가 생깁니다. 취소를 요청한 순간 실행 중이던 쿼리가 아니라 다른 쿼리를 취소해 버릴 위험이 있습니다. 그리 바람직하진 않지만, 아직 오싹함의 정도는 심하지 않습니다. 10점 만점에 2점이나 3점 정도일까요.
하지만 여기에는 더 큰 놀라움이 있습니다. psql은 이 CancelRequest를 항상 암호화하지 않고 보냅니다. 취소 대상 쿼리를 실어 나르는 연결이 가장 엄격한 TLS 설정(sslmode=verify-full, channel_binding=require 등)을 사용하고 있더라도, psql은 그대로 평문으로 취소 요청을 보냅니다.
반면 이 통신의 반대편에 있는 Postgres 서버는 TLS 지원을 갖춘 이후로 계속해서 TLS를 통한 CancelRequest 메시지를 수용해 왔습니다. 하지만 Postgres 17 이전, 즉 불과 18개월도 되지 않은 시점까지는 psql이 기반하고 있는 클라이언트 측 Postgres C 라이브러리 libpq에 CancelRequest를 암호화해서 보내는 기능 자체가 없었습니다.
Postgres 17부터는 libpq에 TLS를 통해 CancelRequest 메시지를 보내는 함수들이 실제로 존재합니다. 그리고 libpq 기반의 많은 드라이버들, 예를 들어 ruby-pg는 이제 이 새로운 암호화 함수들을 사용합니다.
하지만 psql 자체는 여전히 그것들을 사용하지 않습니다. 현재 시점에서도 psql에서 Ctrl-C를 누르면, CancelRequest는 태어난 그날처럼 아무 보호 없이 암호화되지 않은 평문으로 네트워크를 지나갑니다.
저처럼 Postgres 보안에 관심이 있는 사람에게는 이 점이 꽤 불안하게 느껴집니다. 오싹함 수준으로 따지면 적어도 단단한 6점입니다. 여기에는 잠재적인 서비스 거부 공격 가능성이 숨어 있습니다.
Postgres 개발자들이 이 문제를 모르고 있는 것은 아닙니다. psql이 아직 libpq의 암호화 취소 함수를 사용하지 않는 데에는 아키텍처상의 이유가 있습니다. 새 함수들이 시그널 세이프하지 않기 때문에 이를 호출하려면 “훨씬 더 큰 규모의 리팩터링이 필요”하다는 것입니다. 하지만 필요한 리팩터링을 수행하는 패치는 향후 릴리스를 목표로 진행 중입니다.
그리고 Neon의 Heikki는 2년 전에 4바이트 비밀 키가 브루트포스될 위험을 설명했고, 그 결과 20여 년 만의 첫 번째 Postgres 프로토콜 업데이트가 이루어졌습니다. 프로토콜 v3.2는 취소용 비밀 키가 최대 256바이트까지 길어질 수 있다는 점을 제외하면 v3.0과 다르지 않습니다. 하지만 libpq와 psql은 연결 문자열 끝에 min_protocol_version=3.2를 명시적으로 지정하지 않는 한 여전히 이 새 버전을 사용하지 않습니다.
그렇다면 최신 psql을 사용하고, 브루트포스로는 뚫기 어려울 만큼 큰 비밀 키를 얻기 위해 프로토콜 3.2도 명시했다고 가정해 봅시다. 그래도 쿼리를 취소하는 순간, 네트워크 트래픽을 볼 수 있는 누구나, 예를 들어 같은 개방형 WiFi 네트워크에 있는 누구라도 서비스 거부 공격을 수행할 수 있습니다. 구체적으로는 가로챈 취소 요청을 반복해서 재생하기만 하면, 같은 연결에서 앞으로 실행될 모든 쿼리를 계속 취소할 수 있습니다.
CancelRequest 연결이 흔히 암호화되지 않은 채 이동한다는 사실은 Postgres 주변 도구를 개발하는 사람들에게 조금 더 미묘한 영향을 줍니다. 사실, 제가 Postgres 프로토콜의 이 작은 외딴 구석을 더 깊이 파고들게 된 계기도 바로 이것이었습니다.
저는 Elephantshark라는 오픈소스 Postgres 네트워크 트래픽 모니터를 만들고 유지 관리하고 있습니다. Wireshark와 비슷하지만 Postgres에 특화되어 있고 프록시로 구현되어 있습니다.
Elephantshark의 첫 릴리스는 한 번에 하나의 Postgres 연결만 프록시할 수 있었습니다. 제 개인적인 사용 사례에는 그걸로 충분했지만, 현실 세계와 처음 맞닿자 그 제한은 꽤 어리석다는 사실이 드러났습니다.
예를 하나 들면, 이제 여러분은 psql에서 Ctrl-C를 누를 때 Postgres 백엔드로 보내지는 CancelRequest 메시지가 새롭고 별도의 연결을 통해 이동한다는 사실을 알고 있습니다. 또 다른 예로, Bun.SQL이 기본적으로 하나의 쿼리만 보내더라도 클라이언트 10개로 구성된 풀을 즉시, 병렬로 연결한다는 사실도 알고 계셨나요?
이 둘 모두가 한 번에 하나의 연결만 지원하는 구조와 잘 맞지 않는다는 점은 분명합니다. 그래서 Elephantshark는 v0.2에서 동시 연결 지원을 추가했습니다. 그 덕분에 Bun.SQL 관련 문제는 해결됐습니다.
하지만 psql의 Ctrl-C는 여전히 동작하지 않았습니다. 그리고 조금 더 파고들어 보니, CancelRequest 메시지가 암호화되지 않는다는 점이 원인이었습니다.
그 이유는, TLS를 통해 Elephantshark를 경유해 Postgres에 연결할 때 Elephantshark가 보통 TLS의 SNI(Server Name Indication) 확장과 사용자 지정 가능한 접미사를 이용해 대상 서버를 알아내기 때문입니다.
예를 들어 ep-adj-noun-abc1234.region.aws.neon.tech에 대한 연결을 모니터링하려면, elephantshark를 실행한 다음 ep-adj-noun-abc1234.region.aws.neon.tech.local.neon.build로 연결합니다. .local.neon.build의 모든 하위 도메인은 Elephantshark가 실행 중인 127.0.0.1로 해석됩니다. 그리고 Elephantshark는 SNI로 받은 호스트명이 .local.neon.build로 끝나면, 후속 연결을 만들기 전에 그 부분을 제거해야 한다는 사실을 알고 있습니다.
훌륭하죠. 적어도 쿼리에 브레이크를 걸기 전까지는 말입니다. CancelRequest는 암호화되지 않고 이동하므로 SNI가 없고, 따라서 의도된 대상 호스트에 대한 기록도 없습니다. 다행히 Elephantshark는 localhost에서 받아 localhost로 전달해 달라는 요청이 들어오면 이를 인식하고, 메시지를 무한 루프로 보내는 대신 정중하게 중단합니다. 불행히도 Elephantshark v0.3 이전까지는 이것만으로는 쿼리 취소에 조금도 더 가까워지지 못했습니다.
이 문제의 해결책은 사실 Postgres 프록시 세계에서는 이미 익숙한 이야기입니다. 예를 들어 Neon의 프록시에도 들어 있습니다. 일반 클라이언트 연결을 받으면, (프로세스 ID, 비밀 키) 값을 대상 호스트명에 매핑하는 데이터 구조를 갱신합니다. 그리고 이후 SNI 없는 CancelRequest 연결을 받으면, 그 안에 지정된 (프로세스 ID, 비밀 키)를 사용해 대상 호스트명을 조회합니다. Elephantshark v0.3은 이 목적을 위해 Ruby Hash를 유지하므로, 이제는 취소도 할 수 있고 취소 과정을 모니터링할 수도 있습니다.
암호화된 CancelRequest 메시지가 psql에 곧 적용되기를 바랍니다. 그때까지는 보안을 매우 중요하게 생각한다면 다음 중 일부 또는 전부를 실천하세요. Postgres 18과 min_protocol_version=3.2를 사용하기, VPN 사용하기, psql에서 Ctrl-C를 사용하지 않기, 그리고 사용하는 다른 Postgres 클라이언트나 드라이버가 CancelRequest를 암호화하는지 확인하기입니다.
마지막 항목에 대해서는 Elephantshark가 도움이 될 수 있습니다. 그리고 앞으로를 지켜봐 주세요. 가까운 미래에 이런 종류의 점검을 훨씬 더 쉽게 만들 수 있는 아이디어가 하나 있습니다.
부록: Elephantshark 제공, Postgres 프로토콜 v3.2를 사용할 때 psql에서 Ctrl-C를 누르면 무슨 일이 일어나는가
공유:
최신 업데이트만 받아보세요. 스팸은 없습니다.
구독하기
공유:
사례 연구2026년 3월 18일
# How Specific Provisions Thousands of Databases for Coding Agents Using Neon
AI2026년 2월 26일
# 15,000+ Apps Built Over WhatsApp: Inside QwikBuild’s Neon-Powered Architecture
AI2026년 2월 25일
# Where Agents Meet Infrastructure: Encore, Leap, and Neon
Databricks 계열사
Neon 상태 불러오는 중... SF와 전 세계에서 만들었습니다.저작권 Ⓒ 2022 – 2026 Neon, LLC
회사
리소스
커뮤니티
규정 준수