diff --git a/src/backend/tcop/backend_startup.c b/src/backend/tcop/backend_startup.c
index 2a96c81f92..096c798df5 100644
--- a/src/backend/tcop/backend_startup.c
+++ b/src/backend/tcop/backend_startup.c
@@ -128,7 +128,7 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
 	Port	   *port;
 	char		remote_host[NI_MAXHOST];
 	char		remote_port[NI_MAXSERV];
-	StringInfoData ps_data;
+	char	   *ps_data;
 	MemoryContext oldcontext;
 
 	/* Tell fd.c about the long-lived FD associated with the client_sock */
@@ -351,18 +351,9 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
 	 * Now that we have the user and database name, we can set the process
 	 * title for ps.  It's good to do this as early as possible in startup.
 	 */
-	initStringInfo(&ps_data);
-	if (am_walsender)
-		appendStringInfo(&ps_data, "%s ", GetBackendTypeDesc(B_WAL_SENDER));
-	appendStringInfo(&ps_data, "%s ", port->user_name);
-	if (port->database_name[0] != '\0')
-		appendStringInfo(&ps_data, "%s ", port->database_name);
-	appendStringInfoString(&ps_data, port->remote_host);
-	if (port->remote_port[0] != '\0')
-		appendStringInfo(&ps_data, "(%s)", port->remote_port);
-
-	init_ps_display(ps_data.data);
-	pfree(ps_data.data);
+	ps_data = get_ps_data(port);
+	init_ps_display(ps_data);
+	pfree(ps_data);
 
 	set_ps_display("initializing");
 }
@@ -915,3 +906,21 @@ StartupPacketTimeoutHandler(void)
 {
 	_exit(1);
 }
+
+char *
+get_ps_data(Port *port)
+{
+	StringInfoData ps_data;
+
+	initStringInfo(&ps_data);
+	if (am_walsender)
+		appendStringInfo(&ps_data, "%s ", GetBackendTypeDesc(B_WAL_SENDER));
+	appendStringInfo(&ps_data, "%s ", port->user_name);
+	if (port->database_name[0] != '\0')
+		appendStringInfo(&ps_data, "%s ", port->database_name);
+	appendStringInfoString(&ps_data, port->remote_host);
+	if (port->remote_port[0] != '\0')
+		appendStringInfo(&ps_data, "(%s)", port->remote_port);
+
+	return ps_data.data;
+}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index bd42476717..24b9bc0cc0 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -66,6 +66,7 @@
 #include "storage/proc.h"
 #include "storage/procsignal.h"
 #include "storage/sinval.h"
+#include "tcop/backend_startup.h"
 #include "tcop/fastpath.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
@@ -4264,6 +4265,7 @@ void
 PostgresMain(const char *dbname, const char *username)
 {
 	sigjmp_buf	local_sigjmp_buf;
+	char		out_dbname[NAMEDATALEN];
 
 	/* these must be volatile to ensure state is preserved across longjmp: */
 	volatile bool send_ready_for_query = true;
@@ -4365,7 +4367,20 @@ PostgresMain(const char *dbname, const char *username)
 	InitPostgres(dbname, InvalidOid,	/* database to connect to */
 				 username, InvalidOid,	/* role to connect as */
 				 (!am_walsender) ? INIT_PG_LOAD_SESSION_LIBS : 0,
-				 NULL);			/* no out_dbname */
+				 out_dbname);
+
+	if (MyProcPort && unlikely(strcmp(dbname, out_dbname) != 0))
+	{
+		char	   *ps_data;
+
+		strcpy(MyProcPort->database_name, out_dbname);
+
+		ps_data = get_ps_data(MyProcPort);
+		init_ps_display(ps_data);
+		pfree(ps_data);
+
+		set_ps_display("startup");
+	}
 
 	/*
 	 * If the PostmasterContext is still around, recycle the space; we don't
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 5b657a3f13..017a6aa7cf 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -68,6 +68,7 @@
 #include "utils/timeout.h"
 
 static HeapTuple GetDatabaseTuple(const char *dbname);
+static HeapTuple GetDatabaseTupleInternal(Relation relation, const char *dbname);
 static HeapTuple GetDatabaseTupleByOid(Oid dboid);
 static void PerformAuthentication(Port *port);
 static void CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connections);
@@ -97,12 +98,72 @@ static void process_settings(Oid databaseid, Oid roleid);
  * descriptors for both pg_database and its indexes from the shared relcache
  * cache file, and so we can do an indexscan.  criticalSharedRelcachesBuilt
  * tells whether we got the cached descriptors.
+ *
+ * This function also deals with the trickier-than-it-sounds issue of
+ * truncating an overlength incoming database name.  We do not know which
+ * encoding the name is in, so we can't apply pg_encoding_mbcliplen() as
+ * CREATE DATABASE would have done.  We use the heuristic of truncating one
+ * byte at a time until we find a match in pg_database, relying on the
+ * assumption that the name as stored in pg_database is valid according to
+ * some server-side encoding.  This lets us constrain the search using the
+ * fact that all bytes of a multibyte character have their high bit set.
  */
 static HeapTuple
 GetDatabaseTuple(const char *dbname)
 {
-	HeapTuple	tuple;
+	HeapTuple	tuple = NULL;
 	Relation	relation;
+	char		tname[NAMEDATALEN];
+
+	relation = table_open(DatabaseRelationId, AccessShareLock);
+
+	for (int i = NAMEDATALEN - 1;
+		 i >= NAMEDATALEN - MAX_MULTIBYTE_CHAR_LEN;
+		 i--)
+	{
+		strncpy(tname, dbname, sizeof(tname));
+		tname[i] = '\0';
+
+		/*
+		 * Take the first match.  It's theoretically possible that we could
+		 * find more than one match if we continued to try shorter truncations
+		 * (which is what makes this a heuristic).  This is unlikely though.
+		 * We considered failing if there are multiple candidate matches, but
+		 * that cure seems worse than the disease: it might reject cases that
+		 * worked fine before v17.
+		 */
+		tuple = GetDatabaseTupleInternal(relation, tname);
+		if (HeapTupleIsValid(tuple))
+			break;
+
+		/*
+		 * On the first iteration, check if we actually truncated anything. If
+		 * not, then we don't need to bother with the successive-truncation
+		 * heuristic.
+		 */
+		if (i == NAMEDATALEN - 1 && strlen(dbname) < NAMEDATALEN)
+			break;
+
+		/*
+		 * If the bytes at the truncation point are ASCII characters, we know
+		 * that they cannot both be part of the same character, so the
+		 * original truncation by CREATE/ALTER DATABASE would have gone no
+		 * further.
+		 */
+		if (!IS_HIGHBIT_SET(dbname[i]) || !IS_HIGHBIT_SET(dbname[i - 1]))
+			break;
+	}
+
+	table_close(relation, AccessShareLock);
+
+	return tuple;
+}
+
+/* One tuple fetch for GetDatabaseTuple */
+static HeapTuple
+GetDatabaseTupleInternal(Relation relation, const char *dbname)
+{
+	HeapTuple	tuple;
 	SysScanDesc scan;
 	ScanKeyData key[1];
 
@@ -115,11 +176,10 @@ GetDatabaseTuple(const char *dbname)
 				CStringGetDatum(dbname));
 
 	/*
-	 * Open pg_database and fetch a tuple.  Force heap scan if we haven't yet
-	 * built the critical shared relcache entries (i.e., we're starting up
-	 * without a shared relcache cache file).
+	 * Try to fetch the tuple.  Force heap scan if we haven't yet built the
+	 * critical shared relcache entries (i.e., we're starting up without a
+	 * shared relcache cache file).
 	 */
-	relation = table_open(DatabaseRelationId, AccessShareLock);
 	scan = systable_beginscan(relation, DatabaseNameIndexId,
 							  criticalSharedRelcachesBuilt,
 							  NULL,
@@ -133,7 +193,6 @@ GetDatabaseTuple(const char *dbname)
 
 	/* all done */
 	systable_endscan(scan);
-	table_close(relation, AccessShareLock);
 
 	return tuple;
 }
@@ -1011,6 +1070,8 @@ InitPostgres(const char *in_dbname, Oid dboid,
 					 errmsg("database \"%s\" does not exist", in_dbname)));
 		dbform = (Form_pg_database) GETSTRUCT(tuple);
 		dboid = dbform->oid;
+		/* Save the real (possibly truncated) database name */
+		strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname));
 	}
 	else if (!OidIsValid(dboid))
 	{
@@ -1066,8 +1127,9 @@ InitPostgres(const char *in_dbname, Oid dboid,
 		if (HeapTupleIsValid(tuple))
 			datform = (Form_pg_database) GETSTRUCT(tuple);
 
+		/* Note comparison here must be against the truncated DB name */
 		if (!HeapTupleIsValid(tuple) ||
-			(in_dbname && namestrcmp(&datform->datname, in_dbname)))
+			(in_dbname && namestrcmp(&datform->datname, dbname) != 0))
 		{
 			if (in_dbname)
 				ereport(FATAL,
diff --git a/src/include/tcop/backend_startup.h b/src/include/tcop/backend_startup.h
index 993b013afd..6e26c00002 100644
--- a/src/include/tcop/backend_startup.h
+++ b/src/include/tcop/backend_startup.h
@@ -40,5 +40,6 @@ typedef struct BackendStartupData
 } BackendStartupData;
 
 extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
+extern char *get_ps_data(Port *port);
 
 #endif							/* BACKEND_STARTUP_H */
-- 
2.39.5 (Apple Git-154)
