diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index d263903622..1989cfec35 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2109,7 +2109,8 @@ ChooseIndexName(const char *tabname, Oid namespaceId,
  * We know that less than NAMEDATALEN characters will actually be used,
  * so we can truncate the result once we've generated that many.
  *
- * XXX See also ChooseExtendedStatisticNameAddition.
+ * XXX See also ChooseForeignKeyConstraintNameAddition and
+ * ChooseExtendedStatisticNameAddition.
  */
 static char *
 ChooseIndexNameAddition(List *colnames)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index ad385785da..5ecbe4fd8a 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -496,7 +496,8 @@ ChooseExtendedStatisticName(const char *name1, const char *name2,
  * We know that less than NAMEDATALEN characters will actually be used,
  * so we can truncate the result once we've generated that many.
  *
- * XXX see also ChooseIndexNameAddition.
+ * XXX see also ChooseForeignKeyConstraintNameAddition and
+ * ChooseIndexNameAddition.
  */
 static char *
 ChooseExtendedStatisticNameAddition(List *exprs)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d2781cbf19..226b2843ed 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -401,6 +401,7 @@ static ObjectAddress ATExecAddConstraint(List **wqueue,
 					AlteredTableInfo *tab, Relation rel,
 					Constraint *newConstraint, bool recurse, bool is_readd,
 					LOCKMODE lockmode);
+static char * ChooseForeignKeyConstraintNameAddition(List *colnames);
 static ObjectAddress ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 						 IndexStmt *stmt, LOCKMODE lockmode);
 static ObjectAddress ATAddCheckConstraint(List **wqueue,
@@ -7063,7 +7064,7 @@ ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			else
 				newConstraint->conname =
 					ChooseConstraintName(RelationGetRelationName(rel),
-										 strVal(linitial(newConstraint->fk_attrs)),
+										 ChooseForeignKeyConstraintNameAddition(newConstraint->fk_attrs),
 										 "fkey",
 										 RelationGetNamespace(rel),
 										 NIL);
@@ -7082,6 +7083,43 @@ ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	return address;
 }
 
+/*
+ * Generate "name2" for a new foreign key given the list of column names that
+ * reference the referenced table. This will be passed to ChooseConstraintName
+ * along with the parent table name and a suitable label.
+ *
+ * We know that less than NAMEDATALEN characters will actually be used,
+ * so we can truncate the result once we've generated that many.
+ *
+ * XXX see also ChooseExtendedStatisticNameAddition and ChooseIndexNameAddition.
+ */
+static char *
+ChooseForeignKeyConstraintNameAddition(List *colnames)
+{
+	char		buf[NAMEDATALEN * 2];
+	int			buflen = 0;
+	ListCell   *lc;
+
+	buf[0] = '\0';
+	foreach(lc, colnames)
+	{
+		const char *name = strVal(lfirst(lc));
+
+		if (buflen > 0)
+			buf[buflen++] = '_';	/* insert _ between names */
+
+		/*
+		 * At this point we have buflen <= NAMEDATALEN.  name should be less
+		 * than NAMEDATALEN already, but use strlcpy for paranoia.
+		 */
+		strlcpy(buf + buflen, name, NAMEDATALEN);
+		buflen += strlen(buf + buflen);
+		if (buflen >= NAMEDATALEN)
+			break;
+	}
+	return pstrdup(buf);
+}
+
 /*
  * Add a check constraint to a single table and its children.  Returns the
  * address of the constraint added to the parent relation, if one gets added,
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 085c9aba11..d7c9056e8e 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1394,6 +1394,19 @@ update pktable2 set d = 5;
 ERROR:  update or delete on table "pktable2" violates foreign key constraint "fktable2_d_fkey" on table "fktable2"
 DETAIL:  Key (d, e)=(4, 5) is still referenced from table "fktable2".
 drop table pktable2, fktable2;
+-- Test default name of composite foreign keys
+create table singular_pk_table (a int primary key);
+create table composite_pk_table (b int, c int, primary key (b, c));
+create table composite_fk_table (a int, b int, c int, foreign key (a) references singular_pk_table, foreign key (b, c) references composite_pk_table);
+alter table composite_fk_table add foreign key (a, c) references composite_pk_table;
+select conname from pg_constraint where conrelid = 'composite_fk_table'::regclass order by conname;
+           conname
+-----------------------------
+ composite_fk_table_a_c_fkey
+ composite_fk_table_a_fkey
+ composite_fk_table_b_c_fkey
+(3 rows)
+
 --
 -- Test deferred FK check on a tuple deleted by a rolled-back subtransaction
 --
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index 068ab2aab7..cf875582db 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -1030,6 +1030,13 @@ delete from pktable2;
 update pktable2 set d = 5;
 drop table pktable2, fktable2;
 
+-- Test default name of composite foreign keys
+create table singular_pk_table (a int primary key);
+create table composite_pk_table (b int, c int, primary key (b, c));
+create table composite_fk_table (a int, b int, c int, foreign key (a) references singular_pk_table, foreign key (b, c) references composite_pk_table);
+alter table composite_fk_table add foreign key (a, c) references composite_pk_table;
+select conname from pg_constraint where conrelid = 'composite_fk_table'::regclass order by conname;
+
 --
 -- Test deferred FK check on a tuple deleted by a rolled-back subtransaction
 --
