diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index 6788f882a8..b0678e8e97 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -609,6 +609,41 @@ get_control_data(ClusterInfo *cluster, bool live_check)
 	}
 }
 
+/*
+ * subroutine for checking each item in pg_control_data
+ *
+ * This is intended to be a part of CHECK_CTRL_ITEM macro.
+ * item is translated item name to be printed on error
+ * old_invalid, new_invalid, do_not_match is the check results of an item
+ * old/new_invalid are ignored if check_invalid is false.
+ */
+static void
+check_control_data_item(char *item,
+						bool check_invalid, bool old_invalid, bool new_invalid,
+						bool do_not_match)
+{
+	static char *message[] = {
+		"no error", /* should not be used */
+		gettext_noop("souce pg_controldata item is invalid:%s"),
+		gettext_noop("target pg_controldata item is invalid:%s"),
+		gettext_noop("source and target pg_controldata items do not match:%s")
+	};
+	int failure_type = 0;
+
+	if (check_invalid)
+	{
+		if (old_invalid)
+			failure_type = 1;
+		else if (new_invalid)
+			failure_type = 2;
+	}
+
+	if (failure_type == 0 && do_not_match)
+		failure_type = 3;
+
+	if (failure_type > 0)
+		pg_fatal(message[failure_type], item);
+}
 
 /*
  * check_control_data()
@@ -619,38 +654,24 @@ void
 check_control_data(ControlData *oldctrl,
 				   ControlData *newctrl)
 {
-	if (oldctrl->align == 0 || oldctrl->align != newctrl->align)
-		pg_fatal("old and new pg_controldata alignments are invalid or do not match\n"
-				 "Likely one cluster is a 32-bit install, the other 64-bit\n");
+#define CHECK_CTRL_ITEM(member, item, check_invalid)	\
+	check_control_data_item(_(item), check_invalid,						\
+							oldctrl->member == 0, newctrl->member == 0,	\
+							oldctrl->member != newctrl->member)
 
-	if (oldctrl->blocksz == 0 || oldctrl->blocksz != newctrl->blocksz)
-		pg_fatal("old and new pg_controldata block sizes are invalid or do not match\n");
-
-	if (oldctrl->largesz == 0 || oldctrl->largesz != newctrl->largesz)
-		pg_fatal("old and new pg_controldata maximum relation segment sizes are invalid or do not match\n");
-
-	if (oldctrl->walsz == 0 || oldctrl->walsz != newctrl->walsz)
-		pg_fatal("old and new pg_controldata WAL block sizes are invalid or do not match\n");
-
-	if (oldctrl->walseg == 0 || oldctrl->walseg != newctrl->walseg)
-		pg_fatal("old and new pg_controldata WAL segment sizes are invalid or do not match\n");
-
-	if (oldctrl->ident == 0 || oldctrl->ident != newctrl->ident)
-		pg_fatal("old and new pg_controldata maximum identifier lengths are invalid or do not match\n");
-
-	if (oldctrl->index == 0 || oldctrl->index != newctrl->index)
-		pg_fatal("old and new pg_controldata maximum indexed columns are invalid or do not match\n");
-
-	if (oldctrl->toast == 0 || oldctrl->toast != newctrl->toast)
-		pg_fatal("old and new pg_controldata maximum TOAST chunk sizes are invalid or do not match\n");
+	CHECK_CTRL_ITEM(align, "  maximum alignment\n", true);
+	CHECK_CTRL_ITEM(blocksz, "  block size\n", true);
+	CHECK_CTRL_ITEM(largesz, "  large relation segment size\n", true);
+	CHECK_CTRL_ITEM(walsz, "  WAL block size\n", true);
+	CHECK_CTRL_ITEM(walseg, "  WAL segment size\n", true);
+	CHECK_CTRL_ITEM(ident, "  maximum identifier length\n", true);
+	CHECK_CTRL_ITEM(index, "  maximum number of indexed columns\n", true);
+	CHECK_CTRL_ITEM(toast, "  maximum TOAST chunk size\n", true);
 
 	/* large_object added in 9.5, so it might not exist in the old cluster */
-	if (oldctrl->large_object != 0 &&
-		oldctrl->large_object != newctrl->large_object)
-		pg_fatal("old and new pg_controldata large-object chunk sizes are invalid or do not match\n");
+	CHECK_CTRL_ITEM(large_object, "  large-object chunk size\n", true);
 
-	if (oldctrl->date_is_int != newctrl->date_is_int)
-		pg_fatal("old and new pg_controldata date/time storage types do not match\n");
+	CHECK_CTRL_ITEM(date_is_int, "  dates/times are integers\n", false);
 
 	/*
 	 * float8_pass_by_value does not need to match, but is used in
