diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 6cd00d9aaa..4dbedc3e00 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1924,7 +1924,12 @@ StartTransaction(void)
 	Assert(s->prevSecContext == 0);
 
 	/*
-	 * initialize other subsystems for new transaction
+	 * Initialize other subsystems for new transaction.
+	 *
+	 * XXX: Those had better be designed to never issue an ERROR as
+	 * GetUserIdAndSecContext() has been called so as a transaction
+	 * still marked as starting is able to reset what has been set
+	 * by the previous call!
 	 */
 	AtStart_GUC();
 	AtStart_Cache();
@@ -2520,28 +2525,34 @@ AbortTransaction(void)
 	 * check the current transaction state
 	 */
 	is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
-	if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)
+	if (s->state != TRANS_START &&
+		s->state != TRANS_INPROGRESS &&
+		s->state != TRANS_PREPARE)
 		elog(WARNING, "AbortTransaction while in %s state",
 			 TransStateAsString(s->state));
 	Assert(s->parent == NULL);
 
-	/*
-	 * set the current transaction state information appropriately during the
-	 * abort processing
-	 */
-	s->state = TRANS_ABORT;
-
 	/*
 	 * Reset user ID which might have been changed transiently.  We need this
 	 * to clean up in case control escaped out of a SECURITY DEFINER function
 	 * or other local change of CurrentUserId; therefore, the prior value of
 	 * SecurityRestrictionContext also needs to be restored.
 	 *
+	 * If the transaction is aborted when it has been partially started, then
+	 * the user ID does not need to be set to its previous value.
+	 *
 	 * (Note: it is not necessary to restore session authorization or role
 	 * settings here because those can only be changed via GUC, and GUC will
 	 * take care of rolling them back if need be.)
 	 */
-	SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
+	if (s->state != TRANS_START)
+		SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
+
+	/*
+	 * set the current transaction state information appropriately during the
+	 * abort processing
+	 */
+	s->state = TRANS_ABORT;
 
 	/* If in parallel mode, clean up workers and exit parallel mode. */
 	if (IsInParallelMode())
@@ -3013,15 +3024,6 @@ AbortCurrentTransaction(void)
 			}
 			else
 			{
-				/*
-				 * We can get here after an error during transaction start
-				 * (state will be TRANS_START).  Need to clean up the
-				 * incompletely started transaction.  First, adjust the
-				 * low-level state to suppress warning message from
-				 * AbortTransaction.
-				 */
-				if (s->state == TRANS_START)
-					s->state = TRANS_INPROGRESS;
 				AbortTransaction();
 				CleanupTransaction();
 			}
@@ -4355,15 +4357,6 @@ AbortOutOfAnyTransaction(void)
 				}
 				else
 				{
-					/*
-					 * We can get here after an error during transaction start
-					 * (state will be TRANS_START).  Need to clean up the
-					 * incompletely started transaction.  First, adjust the
-					 * low-level state to suppress warning message from
-					 * AbortTransaction.
-					 */
-					if (s->state == TRANS_START)
-						s->state = TRANS_INPROGRESS;
 					AbortTransaction();
 					CleanupTransaction();
 				}
