diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index cdd8788b9e..7120ead751 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -142,6 +142,9 @@ check_and_dump_old_cluster(bool live_check)
 	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
 		new_9_0_populate_pg_largeobject_metadata(&old_cluster, true);
 
+	if (user_opts.check)
+		get_non_default_acl_infos(&old_cluster);
+
 	/*
 	 * While not a check option, we do this now because this is the only time
 	 * the old server is running.
@@ -181,6 +184,143 @@ check_new_cluster(void)
 	check_for_prepared_transactions(&new_cluster);
 }
 
+/*
+ * check_changed_signatures()
+ *
+ * Checks that the old cluster doesn't have non-default ACL's for system objects
+ * which had different signatures in the new cluster.
+ */
+void
+check_changed_signatures(void)
+{
+	PGconn	   *conn;
+	PGresult   *new_res;
+	int			new_ntups;
+	int			i_obj_sig = 0;
+	int			dbnum;
+	bool		need_check;
+	FILE	   *script = NULL;
+	bool		found_incompatible = false;
+	char		output_path[MAXPGPATH];
+
+	if (!user_opts.check)
+		return;
+
+	prep_status("Checking for system objects to grant or revoke privileges");
+
+	for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
+		if (old_cluster.dbarr.dbs[dbnum].non_def_acl_arr.nacls > 0)
+		{
+			need_check = true;
+			break;
+		}
+	/*
+	 * The old cluster doesn't have system objects with non-default ACL so
+	 * quickly exit.
+	 */
+	if (!need_check)
+	{
+		check_ok();
+		return;
+	}
+
+	snprintf(output_path, sizeof(output_path),
+			 "incompatible_objects_for_acl.txt");
+
+	conn = connectToServer(&new_cluster, "template1");
+	new_res = executeQueryOrDie(conn,
+		/* Get relations, languages, functions and procedures */
+		"SELECT pg_catalog.pg_describe_object(refclassid, refobjid, refobjsubid) "
+		"FROM pg_catalog.pg_depend "
+		"WHERE deptype = 'p' AND refclassid IN "
+		"  ('pg_proc'::regclass, 'pg_class'::regclass, 'pg_language'::regclass) "
+		"UNION ALL "
+		/* ...and union it with columns */
+		"SELECT pg_catalog.pg_describe_object(d.refclassid, att.attrelid, att.attnum) "
+		"FROM pg_catalog.pg_depend d "
+		"INNER JOIN pg_catalog.pg_attribute att ON att.attrelid = d.refobjid "
+		"WHERE d.deptype = 'p' AND d.refclassid = 'pg_class'::regclass "
+		"ORDER BY 1;");
+	new_ntups = PQntuples(new_res);
+
+	for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
+	{
+		DbInfo	   *dbinfo = &old_cluster.dbarr.dbs[dbnum];
+		bool		db_used = false;
+		int			aclnum = 0,
+					new_objnum = 0;
+
+		/*
+		 * For every database check system objects with non-default ACL.
+		 *
+		 * AclInfo array is sorted by obj_sig.  This allows us to compare
+		 * AclInfo entries with the query result above efficiently.
+		 */
+		for (aclnum = 0; aclnum < dbinfo->non_def_acl_arr.nacls; aclnum++)
+		{
+			AclInfo	   *aclinfo = &dbinfo->non_def_acl_arr.aclinfos[aclnum];
+			bool		found = false;
+
+			while (new_objnum < new_ntups)
+			{
+				int			ret;
+
+				ret = strcmp(PQgetvalue(new_res, new_objnum, i_obj_sig),
+							 aclinfo->obj_sig);
+				/*
+				 * The new cluster doesn't have an object with same signature,
+				 * exit the loop, report below and check next object.
+				 */
+				if (ret < 0)
+					break;
+				/*
+				 * The new cluster has an object with same signatre, just exit
+				 * the loop.
+				 */
+				else if (ret == 0)
+				{
+					found = true;
+					new_objnum++;
+					break;
+				}
+
+				new_objnum++;
+			}
+
+			if (!found)
+			{
+				found_incompatible = true;
+				if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+					pg_fatal("could not open file \"%s\": %s\n",
+							 output_path, strerror(errno));
+				if (!db_used)
+				{
+					fprintf(script, "In database: %s\n", dbinfo->db_name);
+					db_used = true;
+				}
+				fprintf(script, "  %s\n", aclinfo->obj_sig);
+			}
+		}
+	}
+
+	PQclear(new_res);
+	PQfinish(conn);
+
+	if (script)
+		fclose(script);
+
+	if (found_incompatible)
+	{
+		pg_log(PG_REPORT, "fatal\n");
+		pg_fatal("Your installation contains non-default privileges for system objects\n"
+				 "for which the API has changed.  To perform the upgrade, reset these\n"
+				 "privileges to default.  A list of the problem objects is in the file:\n"
+				 "    %s\n\n", output_path);
+	}
+	else
+		check_ok();
+}
+
 
 void
 report_clusters_compatible(void)
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index d67d3a4894..2d23d83914 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -328,6 +328,80 @@ get_db_and_rel_infos(ClusterInfo *cluster)
 }
 
 
+/*
+ * get_non_default_acl_infos()
+ *
+ * Gets AclInfo array of system functions, procedures and columns information
+ * which have non-default ACL.
+ *
+ * Note: the resulting AclInfo array is assumed to be sorted by obj_sig.
+ */
+void
+get_non_default_acl_infos(ClusterInfo *cluster)
+{
+	int			dbnum;
+
+	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+	{
+		DbInfo	   *dbinfo = &cluster->dbarr.dbs[dbnum];
+		PGconn	   *conn = connectToServer(cluster, dbinfo->db_name);
+		PGresult   *res;
+		AclInfo	   *aclinfos;
+		int			ntups;
+		int			aclnum;
+		int			i_obj_sig = 0;
+
+		res = executeQueryOrDie(conn,
+			/*
+			 * Get relations, languages, functions and procedures.
+			 */
+			"SELECT pg_catalog.pg_describe_object(shd.classid, shd.objid, 0) "
+			"FROM pg_catalog.pg_shdepend shd "
+			"INNER JOIN pg_catalog.pg_depend d ON d.refclassid = shd.classid AND "
+			"  d.refobjid = shd.objid AND "
+			/* get only system objects */
+			"  d.deptype = 'p' "
+			"WHERE shd.deptype = 'a' AND shd.dbid = %d AND shd.objsubid = 0 AND "
+			"  shd.classid IN "
+			"  ('pg_proc'::regclass, 'pg_class'::regclass, 'pg_language'::regclass) "
+			"UNION ALL "
+			/*
+			 * ...and union it with columns. We need to make an attribute
+			 * description manually because Pre-PG 11 had different description
+			 * for attributes.
+			 */
+			"SELECT 'column ' || att.attname || ' of ' || "
+			"  pg_catalog.pg_describe_object(shd.classid, shd.objid, 0) "
+			"FROM pg_catalog.pg_shdepend shd "
+			"INNER JOIN pg_catalog.pg_depend d ON d.refclassid = shd.classid AND "
+			"  d.refobjid = shd.objid AND "
+			/* get only system objects */
+			"  d.deptype = 'p' "
+			"INNER JOIN pg_catalog.pg_attribute att ON att.attrelid = shd.objid AND "
+			"  att.attnum = shd.objsubid "
+			"WHERE shd.deptype = 'a' AND shd.dbid = %d AND "
+			"  shd.classid = 'pg_class'::regclass AND shd.objsubid > 0 "
+			"ORDER BY 1;", dbinfo->db_oid, dbinfo->db_oid);
+		ntups = PQntuples(res);
+
+		aclinfos = (AclInfo *) pg_malloc(sizeof(AclInfo) * ntups);
+
+		for (aclnum = 0; aclnum < ntups; aclnum++)
+		{
+			AclInfo	   *curr = &aclinfos[aclnum];
+
+			curr->obj_sig = pg_strdup(PQgetvalue(res, aclnum, i_obj_sig));
+		}
+
+		PQclear(res);
+		PQfinish(conn);
+
+		dbinfo->non_def_acl_arr.aclinfos = aclinfos;
+		dbinfo->non_def_acl_arr.nacls = ntups;
+	}
+}
+
+
 /*
  * get_db_infos()
  *
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 5154a7160d..c1a41939fe 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -117,6 +117,7 @@ main(int argc, char **argv)
 	start_postmaster(&new_cluster, true);
 
 	check_new_cluster();
+	check_changed_signatures();
 	report_clusters_compatible();
 
 	pg_log(PG_REPORT,
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 729f86aa32..531d5c915b 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -149,6 +149,21 @@ typedef struct
 	int			nrels;
 } RelInfoArr;
 
+/*
+ * Structure to store objects information to check if it changed its signature.
+ */
+typedef struct
+{
+	char	   *obj_sig;		/* objects signature returned by
+								 * pg_describe_object() */
+} AclInfo;
+
+typedef struct
+{
+	AclInfo	   *aclinfos;
+	int			nacls;
+} AclInfoArr;
+
 /*
  * The following structure represents a relation mapping.
  */
@@ -185,6 +200,8 @@ typedef struct
 	char	   *db_ctype;
 	int			db_encoding;
 	RelInfoArr	rel_arr;		/* array of all user relinfos */
+	AclInfoArr	non_def_acl_arr;	/* array of objects info with non default
+									 * ACL */
 } DbInfo;
 
 typedef struct
@@ -333,6 +350,7 @@ extern OSInfo os_info;
 void		output_check_banner(bool live_check);
 void		check_and_dump_old_cluster(bool live_check);
 void		check_new_cluster(void);
+void		check_changed_signatures(void);
 void		report_clusters_compatible(void);
 void		issue_warnings_and_set_wal_level(void);
 void		output_completion_banner(char *analyze_script_file_name,
@@ -392,6 +410,7 @@ FileNameMap *gen_db_file_maps(DbInfo *old_db,
 							  DbInfo *new_db, int *nmaps, const char *old_pgdata,
 							  const char *new_pgdata);
 void		get_db_and_rel_infos(ClusterInfo *cluster);
+void		get_non_default_acl_infos(ClusterInfo *cluster);
 void		print_maps(FileNameMap *maps, int n,
 					   const char *db_name);
 
