fivenines
3/25

Build Your Own PostgreSQL

The Wire Protocol and Session Lifecycle

Time
6 min
Prerequisites
Processes Memory And The Shared System

What You Will Learn

  • Understand the conversation before SQL in a PostgreSQL-like database
  • Understand session state is the product in a PostgreSQL-like database
  • Understand session state machine in a PostgreSQL-like database
  • Understand why a bare stream falls short in a PostgreSQL-like database
session lifecyclewire protocolwireprotocolsessionlifecycleconversationbeforesqlstate

The conversation before SQL

Before a single query can mean anything, a connection has to become a session. An application opens a network connection and wants to talk in SQL, but the server cannot immediately trust the client or assume the session will behave. The wire protocol is the grammar of that conversation. It defines how a client starts, how authentication proceeds, how queries are submitted, how results return, and how errors interrupt the flow without leaving the server confused.

A Postgre-like protocol is not just a transport for query strings. It is a state machine. At connection time, the client sends startup information: user, database, parameters, and sometimes protocol options. The server checks whether the requested identity and database are allowed. Authentication may involve passwords, certificates, local trust, or external systems. Only after that boundary is crossed does the server treat the connection as a session capable of running SQL.

Session state is the product

Once authenticated, the session accumulates state. It has settings, a current transaction state, prepared statements, temporary objects, search paths, and error status. This is why a connection is more than a socket. It is a long-lived context in which later messages can depend on earlier ones. A query can set a parameter, create a temporary table, prepare a statement, start a transaction, fail, recover, and continue. The protocol has to make those transitions explicit enough that both client and server agree on what is happening.

The simplest query path sends SQL text and waits for a complete response. The server parses, plans, executes, and returns rows or a command result. A richer path separates parsing, binding, describing, executing, and syncing. That split lets clients prepare statements, supply parameters later, inspect result shapes, and reuse work. It also makes error handling more precise. If parsing succeeds but binding fails, the server and client need to know which named object remains valid and which part of the exchange must be abandoned.

Session state machine

Why a bare stream falls short

A bare stream of independent SQL strings can work for a small tool, but it misses the durable shape of real application conversations. Prepared statements have nowhere natural to live. Transaction failure is ambiguous. Parameter types are guessed repeatedly. Errors can desynchronize client and server if the client sends multiple requests before reading all responses. A protocol without session state eventually rebuilds session state badly.

The other failure mode is a protocol that becomes too clever. If every message tries to expose internal planner choices, storage details, or lock behavior, the server becomes trapped by its own interface. The wire protocol should reveal stable conversational concepts, not every internal mechanism. Clients need to know when a statement is ready, what columns a result will contain, whether a transaction failed, and when the server is ready for the next request. They do not need to know which buffer was pinned or which join algorithm won.

Boundaries and interruptions

Authentication is the first hard boundary because it decides whose session this is. Authorization later decides what that session can do. Keeping those ideas separate clarifies the design. Authentication answers, "Who are you?" Authorization answers, "May you touch this object?" The startup sequence establishes identity and initial database context. Later semantic analysis and execution consult privileges for tables, functions, schemas, and operations.

Error handling gives the protocol much of its character. A syntax error outside a transaction may simply return an error and then Ready. The same error inside a transaction may put the transaction into a failed state where only rollback can restore normal work. This protects atomicity. The database cannot pretend part of a transaction is fine after a statement failed in a way that may have left effects uncertain. The protocol carries that state back to the client so application code can respond deliberately.

Cancellation is another essential conversation. A long query may need to stop without killing the whole session. In a process-based architecture, cancellation can be signaled to the backend running the query. The server has to interrupt at safe points, unwind execution, release resources, and report an error. This is a small feature at the application level and a deep discipline inside the engine.

The session lifecycle also shapes pooling. Since sessions carry state, reusing a connection for another application request is not free. The pooler has to know whether the session is clean: no open transaction, no temporary state that matters, no changed settings that will surprise the next user. A database protocol that exposes readiness and transaction status gives poolers enough information to be safe.

Into SQL meaning

By the time a SQL string leaves the protocol layer, it has a user, a database, session settings, and a transaction context. It is no longer just text from the network. It is an authenticated request inside a living conversation. The next transformation is linguistic: the database has to take that text and understand it as a relational statement.

Next step

See what actually stuck.

Take the practice scenarios now.