Protocol Greasing During PostgreSQL 19 Beta: Inverting Postel's Law for Wire-Protocol Evolvability
The Core Problem: Protocol Ossification
PostgreSQL's frontend/backend wire protocol has been stuck at version 3.0 since 2003. Each attempt to evolve it — whether bumping the minor version or introducing protocol extensions via the _pq_.* parameter namespace and NegotiateProtocolVersion message — runs into a structural hazard well-known to IETF protocol designers: ossification. When a protocol field is technically negotiable but in practice never varies, middleboxes, connection poolers (PgBouncer, Odyssey), alternative server implementations (CockroachDB, YugabyteDB, Amazon RDS Proxy), and client libraries tend to hardcode assumptions around the single observed value. The moment the real implementation tries to exercise the negotiation machinery, deployments break in the field — not because of a bug in PostgreSQL, but because peers never tested their negotiation code paths.
The canonical mitigation, pioneered by TLS 1.3 and formalized in the IETF draft Jacob cites (draft-edm-protocol-greasing), is GREASE: Generate Random Extensions And Sustain Extensibility. The idea is to routinely send values that no one understands, forcing every peer implementation to exercise its "unknown value" code path on every connection. Anything that breaks, breaks loudly and early, giving the ecosystem time to fix bugs before a real new feature is deployed.
Inverting Postel's Law
Jacob's framing is precise and worth dwelling on. Postel's Law ("be conservative in what you send, liberal in what you accept") is the traditional interoperability maxim, but it is now widely regarded as actively harmful for evolvability: liberal acceptance lets broken peers survive undetected, while conservative sending means negotiation code paths stay cold. Greasing inverts this: libpq becomes liberal in what it sends (advertising a bogus minor version and at least one bogus _pq_.* protocol extension), and strict in what it accepts — if the server does not echo back a NegotiateProtocolVersion message correctly identifying the unsupported bits, libpq fails the connection outright.
This is an aggressive stance. It deliberately surfaces peer bugs as connection failures during beta. The safety valve is the existing max_protocol_version libpq connection option: a user who hits a broken proxy can set max_protocol_version=3.0 to disable greasing and restore the pre-grease behavior. The explicit social contract in Jacob's plan is that users should file a bug against the peer implementation before reaching for that escape hatch.
Scope and Lifecycle of the Experiment
The plan has a carefully constrained blast radius:
- Grease only during 19 beta. The patch is committed early in the cycle, then reverted partway through beta, tracked as a mid-beta Open Item. This is critical: greasing is a testing probe, not a shipped feature. PostgreSQL 19 GA will not grease.
- Grease two dimensions: the minor protocol version number, and at least one protocol extension parameter. This exercises both the version-negotiation path and the extension-negotiation path in
NegotiateProtocolVersion handling.
- Provide a documented escape hatch via
max_protocol_version=3.0, so beta testers are never truly stuck.
The goal is not to find PostgreSQL bugs — it's to find bugs in everyone else's implementations while the beta community is paying attention, so that when PostgreSQL actually does bump the protocol (for whatever future feature motivates it), the ecosystem is ready.
The Communication Problem
The second half of the thread pivots from the technical mechanism to a surprisingly thorny documentation question. When a beta user hits a grease-induced failure, libpq's error message needs to point them somewhere. Jacob identifies a tension:
- The official docs (
libpq-connect.html#LIBPQ-CONNECT-MAX-PROTOCOL-VERSION) are authoritative and permanent, but constrained in tone, slow to update, and awkward for content that will become historical after beta ends.
- The wiki (
wiki.postgresql.org/wiki/Grease) allows a conversational FAQ voice, fast iteration based on real user reports, and a natural home for post-beta retrospective content — but is a vandalism target if libpq's error path links directly to it.
Tom Lane's response is consequential here: as a core committer with long-standing authority over project infrastructure norms, his concurrence that the main docs are "a less-good place" effectively clears the path for the wiki approach. He confirms the wiki can be locked down, but only via a coarse-grained mechanism where no one can edit a locked page until a wiki admin unlocks it — there is no ACL allowing committers-only edits. That's a workable if awkward tradeoff: edits require coordination with a wiki admin, but the page is safe from drive-by vandalism given that its URL will appear in error messages shipped in libpq.
Jacob's subsequent drafting work explores a different concern: whether the wiki page should solicit reports from users who hit greasing failures, to measure whether the campaign is actually surfacing bugs. He ultimately removes that call to action, apparently concluding that directing confused beta users to a mailing list without a clear triage story would create more noise than signal. This is a reasonable call but leaves a gap: there is no systematic feedback loop to quantify how many peer implementations were found broken, which would be useful data for deciding when the ecosystem is actually ready for a real protocol bump.
Design Tradeoffs Worth Noting
- Fail-closed vs. fail-open on greasing. The patch fails the connection when the server doesn't acknowledge the grease. An alternative would be to log a warning and proceed. Fail-closed is the right call for a beta probe because silent warnings get ignored; it's also consistent with how TLS GREASE works (a peer that mishandles GREASE values causes handshake failure).
- Revert mid-beta. Rather than leaving grease on through RC and GA, it's reverted partway through beta. This protects GA users from any residual ecosystem breakage while still getting broad coverage from the beta population. The Open Item mechanism ensures the revert isn't forgotten.
- Per-connection opt-out granularity.
max_protocol_version is a libpq connection parameter, not a compile-time or global setting. A user with one broken proxy can scope the workaround tightly rather than disabling grease globally.
What This Signals About Protocol Evolution Strategy
This thread is small in volume but significant in what it establishes: PostgreSQL is adopting modern IETF-style protocol hygiene practices. The project has historically been cautious to the point of stasis about wire-protocol changes, precisely because of the ossification concerns greasing addresses. Successfully running a grease campaign during 19 beta would be a precondition — both technical and social — for any future protocol 3.x or 4.0 work. If peer implementations turn out to be broadly broken, the project learns that now. If they turn out to be mostly fine, the project gains confidence to actually ship protocol-level features.