From a80d1ee305431285301e5ef8abe7290fe4174361 Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Tue, 25 Aug 2026 08:34:50 -0700
Subject: [PATCH] libpq: Stop greasing protocol connections

This reverts commit 4966bd3ed95e0d02bf220c4bad2b292963827dd4, which
introduced the 19beta grease campaign, now that Beta 3 has been stamped.
(The reservation and documentation for the grease version code, done in
d8d7c5dc8f, remains.)

Discussion: https://postgr.es/m/CAOYmi%2Bkqt_gn-wvUjJG1j3MM4LDDsRMURSPz2eMxfABu0iGtpw%40mail.gmail.com
Backpatch-through: 19
---
 doc/src/sgml/libpq.sgml                       | 17 ------
 doc/src/sgml/protocol.sgml                    | 11 ----
 src/interfaces/libpq/libpq-int.h              |  1 -
 src/interfaces/libpq/fe-connect.c             | 51 ++++--------------
 src/interfaces/libpq/fe-misc.c                | 18 -------
 src/interfaces/libpq/fe-protocol3.c           | 53 ++-----------------
 .../modules/libpq_pipeline/libpq_pipeline.c   |  6 +--
 7 files changed, 16 insertions(+), 141 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 123e7f03902..68487a3954f 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -2211,23 +2211,6 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
      <varlistentry id="libpq-connect-max-protocol-version" xreflabel="max_protocol_version">
       <term><literal>max_protocol_version</literal></term>
       <listitem>
-       <note>
-        <para>
-        During the PostgreSQL 19 beta period, libpq connections that do not
-        specify a <literal>max_protocol_version</literal> will "grease" the
-        handshake by sending unsupported startup parameters, including version
-        <literal>3.9999</literal>, in order to identify software that does not
-        correctly negotiate the connection. This replaces the default behavior
-        described below.
-        </para>
-        <para>
-        If you know that a server doesn't properly implement protocol version
-        negotiation, you can set <literal>max_protocol_version=3.0</literal> to
-        revert to the standard behavior (preferably after notifying the server's
-        maintainers that their software needs to be fixed).
-        </para>
-       </note>
-
        <para>
         Specifies the protocol version to request from the server.
         The default is to use version <literal>3.0</literal> of the
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 49f81676712..89ac680efd5 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -198,17 +198,6 @@
     by default.
    </para>
 
-   <note>
-     <para>
-      During the PostgreSQL 19 beta period, libpq will instead default to
-      requesting protocol version 3.9999, to test that servers and middleware
-      properly implement protocol version negotiation. Servers that support
-      negotiation will automatically downgrade to version 3.2 or 3.0. Users can
-      bypass this beta-only behavior by explicitly setting
-      <literal>max_protocol_version=3.0</literal> in their connection string.
-     </para>
-   </note>
-
    <para>
     A single server can support multiple protocol versions.  The initial
     startup-request message tells the server which protocol version the client
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index a737d1db457..933ba0d99d5 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -965,7 +965,6 @@ extern char *libpq_ngettext(const char *msgid, const char *msgid_plural, unsigne
 
 extern void libpq_append_error(PQExpBuffer errorMessage, const char *fmt, ...) pg_attribute_printf(2, 3);
 extern void libpq_append_conn_error(PGconn *conn, const char *fmt, ...) pg_attribute_printf(2, 3);
-extern void libpq_append_grease_info(PGconn *conn);
 
 /*
  * These macros are needed to let error-handling code be portable between
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index ee398f13998..ec98c58a407 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -91,9 +91,8 @@ static int	ldapServiceLookup(const char *purl, PQconninfoOption *options,
 
 /* This is part of the protocol so just define it */
 #define ERRCODE_INVALID_PASSWORD "28P01"
-/* These too */
+/* This too */
 #define ERRCODE_CANNOT_CONNECT_NOW "57P03"
-#define ERRCODE_PROTOCOL_VIOLATION "08P01"
 
 /*
  * Cope with the various platform-specific ways to spell TCP keepalive socket
@@ -2150,13 +2149,15 @@ pqConnectOptions2(PGconn *conn)
 	else
 	{
 		/*
-		 * Default to PG_PROTOCOL_GREASE, which is larger than all real
-		 * versions, to test negotiation. The server should automatically
-		 * downgrade to a supported version.
-		 *
-		 * This behavior is for 19beta only. It will be reverted before RC1.
+		 * To not break connecting to older servers/poolers that do not yet
+		 * support NegotiateProtocolVersion, default to the 3.0 protocol at
+		 * least for a while longer. Except when min_protocol_version is set
+		 * to something larger, then we might as well default to the latest.
 		 */
-		conn->max_pversion = PG_PROTOCOL_GREASE;
+		if (conn->min_pversion > PG_PROTOCOL(3, 0))
+			conn->max_pversion = PG_PROTOCOL_LATEST;
+		else
+			conn->max_pversion = PG_PROTOCOL(3, 0);
 	}
 
 	if (conn->min_pversion > conn->max_pversion)
@@ -4162,32 +4163,6 @@ keep_going:						/* We will come back to here until there is
 					/* Check to see if we should mention pgpassfile */
 					pgpassfileWarning(conn);
 
-					/*
-					 * ...and whether we should mention grease. If the error
-					 * message contains the PG_PROTOCOL_GREASE number (in
-					 * major.minor, decimal, or hex format) or a complaint
-					 * about a protocol violation before we've even started an
-					 * authentication exchange, it's probably caused by a
-					 * grease interaction.
-					 */
-					if (conn->max_pversion == PG_PROTOCOL_GREASE &&
-						!conn->auth_req_received)
-					{
-						const char *sqlstate = PQresultErrorField(conn->result,
-																  PG_DIAG_SQLSTATE);
-
-						if ((sqlstate &&
-							 strcmp(sqlstate, ERRCODE_PROTOCOL_VIOLATION) == 0) ||
-							(conn->errorMessage.len > 0 &&
-							 (strstr(conn->errorMessage.data, "3.9999") ||
-							  strstr(conn->errorMessage.data, "206607") ||
-							  strstr(conn->errorMessage.data, "3270F") ||
-							  strstr(conn->errorMessage.data, "3270f"))))
-						{
-							libpq_append_grease_info(conn);
-						}
-					}
-
 					CONNECTION_FAILED();
 				}
 				/* Handle NegotiateProtocolVersion */
@@ -4418,14 +4393,6 @@ keep_going:						/* We will come back to here until there is
 					goto error_return;
 				}
 
-				if (conn->max_pversion == PG_PROTOCOL_GREASE &&
-					conn->pversion == PG_PROTOCOL_GREASE)
-				{
-					libpq_append_conn_error(conn, "server incorrectly accepted \"grease\" protocol version 3.9999 without negotiation");
-					libpq_append_grease_info(conn);
-					goto error_return;
-				}
-
 				/* Almost there now ... */
 				conn->status = CONNECTION_CHECK_TARGET;
 				goto keep_going;
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 31bc436ac39..73d10e5cae5 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -1567,21 +1567,3 @@ libpq_append_conn_error(PGconn *conn, const char *fmt, ...)
 
 	appendPQExpBufferChar(&conn->errorMessage, '\n');
 }
-
-/*
- * For 19beta only, some protocol errors will have additional information
- * appended to help with the "grease" campaign.
- */
-void
-libpq_append_grease_info(PGconn *conn)
-{
-	/* translator: %s is a URL */
-	libpq_append_conn_error(conn,
-							"\tThis indicates a bug in either the server being contacted\n"
-							"\tor a proxy handling the connection. Please consider\n"
-							"\treporting this to the maintainers of that software.\n"
-							"\tFor more information, including instructions on how to\n"
-							"\twork around this issue for now, visit\n"
-							"\t\t%s",
-							"https://wiki.postgresql.org/wiki/Grease");
-}
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 79099301abd..1fd427cb9be 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1445,15 +1445,6 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
 {
 	int			their_version;
 	int			num;
-	bool		found_test_protocol_negotiation;
-	bool		expect_test_protocol_negotiation;
-
-	/*
-	 * During 19beta only, if protocol grease is in use, assume that it's the
-	 * cause of any invalid messages encountered below. We'll print extra
-	 * information for the end user in that case.
-	 */
-	bool		need_grease_info = (conn->max_pversion == PG_PROTOCOL_GREASE);
 
 	if (pqGetInt(&their_version, 4, conn) != 0)
 		goto eof;
@@ -1514,7 +1505,6 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
 								PG_PROTOCOL_MAJOR(conn->min_pversion),
 								PG_PROTOCOL_MINOR(conn->min_pversion));
 
-		need_grease_info = false;	/* this is valid server behavior */
 		goto failure;
 	}
 
@@ -1522,12 +1512,9 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
 	conn->pversion = their_version;
 
 	/*
-	 * Check that all expected unsupported parameters are reported by the
-	 * server.
+	 * We don't currently request any protocol extensions, so we don't expect
+	 * the server to reply with any either.
 	 */
-	found_test_protocol_negotiation = false;
-	expect_test_protocol_negotiation = (conn->max_pversion == PG_PROTOCOL_GREASE);
-
 	for (int i = 0; i < num; i++)
 	{
 		if (pqGets(&conn->workBuffer, conn))
@@ -1539,30 +1526,8 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
 			libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported unsupported parameter name without a \"%s\" prefix (\"%s\")", "_pq_.", conn->workBuffer.data);
 			goto failure;
 		}
-
-		/* Check if this is the expected test parameter */
-		if (expect_test_protocol_negotiation &&
-			strcmp(conn->workBuffer.data, "_pq_.test_protocol_negotiation") == 0)
-		{
-			found_test_protocol_negotiation = true;
-		}
-		else
-		{
-			libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")",
-									conn->workBuffer.data);
-			goto failure;
-		}
-	}
-
-	/*
-	 * If we requested protocol grease, the server must report
-	 * _pq_.test_protocol_negotiation as unsupported. This ensures
-	 * comprehensive NegotiateProtocolVersion implementation.
-	 */
-	if (expect_test_protocol_negotiation && !found_test_protocol_negotiation)
-	{
-		libpq_append_conn_error(conn, "server did not report the unsupported \"%s\" parameter in its protocol negotiation message",
-								"_pq_.test_protocol_negotiation");
+		libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")",
+								conn->workBuffer.data);
 		goto failure;
 	}
 
@@ -1571,8 +1536,6 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
 eof:
 	libpq_append_conn_error(conn, "received invalid protocol negotiation message: message too short");
 failure:
-	if (need_grease_info)
-		libpq_append_grease_info(conn);
 	conn->asyncStatus = PGASYNC_READY;
 	pqSaveErrorResult(conn);
 	return 1;
@@ -2540,14 +2503,6 @@ build_startup_packet(const PGconn *conn, char *packet,
 	if (conn->client_encoding_initial && conn->client_encoding_initial[0])
 		ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);
 
-	/*
-	 * Add the test_protocol_negotiation option when greasing, to test that
-	 * servers properly report unsupported protocol options in addition to
-	 * unsupported minor versions.
-	 */
-	if (conn->pversion == PG_PROTOCOL_GREASE)
-		ADD_STARTUP_OPTION("_pq_.test_protocol_negotiation", "");
-
 	/* Add any environment-driven GUC settings needed */
 	for (next_eo = options; next_eo->envName; next_eo++)
 	{
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 1660a68955e..ad007038dc9 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -1363,7 +1363,7 @@ test_protocol_version(PGconn *conn)
 	Assert(max_protocol_version_index >= 0);
 
 	/*
-	 * Test default protocol_version (GREASE - should negotiate down to 3.2)
+	 * Test default protocol_version
 	 */
 	vals[max_protocol_version_index] = "";
 	conn = PQconnectdbParams(keywords, vals, false);
@@ -1373,8 +1373,8 @@ test_protocol_version(PGconn *conn)
 				 PQerrorMessage(conn));
 
 	protocol_version = PQfullProtocolVersion(conn);
-	if (protocol_version != 30002)
-		pg_fatal("expected 30002, got %d", protocol_version);
+	if (protocol_version != 30000)
+		pg_fatal("expected 30000, got %d", protocol_version);
 
 	PQfinish(conn);
 
-- 
2.34.1

