From d6c9cf9cbf141a46b4a4569b395770b0f73a81e7 Mon Sep 17 00:00:00 2001
From: Shlok Kyal <shlok.kyal.oss@gmail.com>
Date: Sat, 11 Apr 2026 23:05:43 +0530
Subject: [PATCH v5 2/3] Support EXCEPT for ALL SEQUENCES in CREATE PUBLICATION

Extend CREATE PUBLICATION ... FOR ALL SEQUENCES to support the
EXCEPT syntax. This allows one or more sequences to be excluded. The
publisher will not send the data of excluded sequences to the subscriber.

Example:
CREATE PUBLICATION pub1 FOR ALL SEQUENCES EXCEPT (SEQUENCE s1, s2);
---
 doc/src/sgml/catalogs.sgml                |  8 +--
 doc/src/sgml/logical-replication.sgml     |  6 +-
 doc/src/sgml/ref/create_publication.sgml  | 37 ++++++++---
 src/backend/catalog/pg_publication.c      | 62 +++++++++++++------
 src/backend/commands/publicationcmds.c    | 51 ++++++++++-----
 src/backend/parser/gram.y                 | 30 ++++++++-
 src/bin/pg_dump/pg_dump.c                 | 56 +++++++++++++----
 src/bin/pg_dump/pg_dump.h                 |  1 +
 src/bin/pg_dump/t/002_pg_dump.pl          | 22 +++++++
 src/bin/psql/describe.c                   | 73 ++++++++++++++++++++--
 src/bin/psql/tab-complete.in.c            | 12 ++++
 src/include/catalog/pg_publication.h      |  3 +-
 src/include/nodes/parsenodes.h            |  5 +-
 src/test/regress/expected/publication.out | 59 +++++++++++++++++-
 src/test/regress/sql/publication.sql      | 28 ++++++++-
 src/test/subscription/t/037_except.pl     | 75 +++++++++++++++++++++++
 16 files changed, 454 insertions(+), 74 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 4b474c13917..5f6c73c3742 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7099,7 +7099,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        (references <link linkend="catalog-pg-class"><structname>pg_class</structname></link>.<structfield>oid</structfield>)
       </para>
       <para>
-       Reference to table
+       Reference to table or sequence
       </para></entry>
      </row>
 
@@ -7108,8 +7108,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <structfield>prexcept</structfield> <type>bool</type>
       </para>
       <para>
-       True if the table is excluded from the publication. See
-       <link linkend="sql-createpublication-params-for-except-table"><literal>EXCEPT</literal></link>.
+       True if the table or the sequence is excluded from the publication. See
+       <link linkend="sql-createpublication-params-for-except"><literal>EXCEPT</literal></link>.
       </para></entry>
      </row>
 
@@ -7118,7 +7118,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <structfield>prqual</structfield> <type>pg_node_tree</type>
       </para>
       <para>Expression tree (in <function>nodeToString()</function>
-      representation) for the relation's publication qualifying condition. Null
+      representation) for the table's publication qualifying condition. Null
       if there is no publication qualifying condition.</para></entry>
      </row>
 
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 9e7868487de..eb0b66491d3 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -119,7 +119,11 @@
    <xref linkend="logical-replication-sequences"/>. When a publication is
    created with <literal>FOR ALL TABLES</literal>, a table or set of tables can
    be explicitly excluded from publication using the
-   <link linkend="sql-createpublication-params-for-except-table"><literal>EXCEPT</literal></link>
+   <link linkend="sql-createpublication-params-for-except"><literal>EXCEPT</literal></link>
+   clause. Similarly, when a publication is created with
+   <literal>FOR ALL SEQUENCES</literal>, a sequence or set of sequences can be
+   explicitly excluded from publication using the
+   <link linkend="sql-createpublication-params-for-except"><literal>EXCEPT</literal></link>
    clause.
   </para>
 
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index f82d640e6ca..df736e74d2f 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -33,7 +33,7 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
 <phrase>and <replaceable class="parameter">publication_all_object</replaceable> is one of:</phrase>
 
     ALL TABLES [ EXCEPT ( <replaceable class="parameter">except_table_object</replaceable> [, ... ] ) ]
-    ALL SEQUENCES
+    ALL SEQUENCES [ EXCEPT ( <replaceable class="parameter">except_sequence_object</replaceable> [, ... ] ) ]
 
 <phrase>and <replaceable class="parameter">table_and_columns</replaceable> is:</phrase>
 
@@ -46,6 +46,10 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
 <phrase>and <replaceable class="parameter">table_object</replaceable> is:</phrase>
 
    [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ]
+
+<phrase>and <replaceable class="parameter">except_sequence_object</replaceable> is:</phrase>
+
+    SEQUENCE <replaceable class="parameter">sequence_name</replaceable> [, ... ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -189,15 +193,18 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
      <para>
       Only persistent sequences are included in the publication. Temporary
       sequences and unlogged sequences are excluded from the publication.
+      Sequences listed in the <literal>EXCEPT</literal> clause are excluded from
+      the publication.
      </para>
     </listitem>
    </varlistentry>
 
-   <varlistentry id="sql-createpublication-params-for-except-table">
+   <varlistentry id="sql-createpublication-params-for-except">
     <term><literal>EXCEPT</literal></term>
     <listitem>
      <para>
-      This clause specifies a list of tables to be excluded from the
+      This clause specifies the tables or sequences to be excluded from an
+      <literal>ALL TABLES</literal> or <literal>ALL SEQUENCES</literal>
       publication.
      </para>
      <para>
@@ -217,9 +224,10 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
      </para>
      <para>
       There can be a case where a subscription includes multiple publications.
-      In such a case, a table or partition that is included in one publication
-      but excluded (explicitly or implicitly) by the <literal>EXCEPT</literal>
-      clause of another is considered included for replication.
+      In such a case, a table, partition or sequence that is included in one
+      publication but excluded (explicitly or implicitly) by the
+      <literal>EXCEPT</literal> clause of another is considered included for
+      replication.
      </para>
     </listitem>
    </varlistentry>
@@ -547,11 +555,20 @@ CREATE PUBLICATION all_tables_except FOR ALL TABLES EXCEPT (TABLE users, departm
   </para>
 
   <para>
-   Create a publication that publishes all sequences for synchronization, and
-   all changes in all tables except <structname>users</structname> and
-   <structname>departments</structname>:
+   Create a publication that publishes all sequences for synchronization except
+   <structname>seq1</structname> and <structname>seq2</structname>:
+<programlisting>
+CREATE PUBLICATION all_sequences_except FOR ALL SEQUENCES EXCEPT (SEQUENCE seq1, seq2);
+</programlisting>
+  </para>
+
+  <para>
+   Create a publication that publishes all sequences for synchronization except
+   <structname>seq1</structname> and <structname>seq2</structname>, and all
+   changes in all tables except
+   <structname>users</structname> and <structname>departments</structname>:
 <programlisting>
-CREATE PUBLICATION all_sequences_tables_except FOR ALL SEQUENCES, ALL TABLES EXCEPT (TABLE users, departments);
+CREATE PUBLICATION all_sequences_tables_except FOR ALL SEQUENCES EXCEPT (SEQUENCE seq1, seq2), ALL TABLES EXCEPT (TABLE users, departments);
 </programlisting>
   </para>
  </refsect1>
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 5fb025eddd7..de264dbed2b 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -51,18 +51,26 @@ typedef struct
 /*
  * Check if relation can be in given publication and throws appropriate
  * error if not.
+ *
+ * 'pubrelkind' is the relkind accepted by the publication clause,
+ * while 'targetrelkind' is the relkind of the relation being added.
+ * Error if they are not compatible.
  */
 static void
-check_publication_add_relation(PublicationRelInfo *pri)
+check_publication_add_relation(PublicationRelInfo *pri, char pubrelkind)
 {
 	Relation	targetrel = pri->relation;
+	char		targetrelkind = RelationGetForm(targetrel)->relkind;
 	const char *relname;
 	const char *errormsg;
 
 	if (pri->except)
 	{
 		relname = RelationGetQualifiedRelationName(targetrel);
-		errormsg = gettext_noop("cannot specify relation \"%s\" in the publication EXCEPT clause");
+		if (pubrelkind == RELKIND_SEQUENCE)
+			errormsg = gettext_noop("cannot specify \"%s\" in the publication EXCEPT (SEQUENCE) clause");
+		else
+			errormsg = gettext_noop("cannot specify \"%s\" in the publication EXCEPT (TABLE) clause");
 	}
 	else
 	{
@@ -77,13 +85,23 @@ check_publication_add_relation(PublicationRelInfo *pri)
 				 errmsg(errormsg, relname),
 				 errdetail("This operation is not supported for individual partitions.")));
 
-	/* Must be a regular or partitioned table */
-	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
-		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
+	/*
+	 * Must be a regular or partitioned table when specified in FOR TABLE or
+	 * EXCEPT table list
+	 */
+	if (pubrelkind == RELKIND_RELATION && targetrelkind != RELKIND_RELATION &&
+		targetrelkind != RELKIND_PARTITIONED_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg(errormsg, relname),
+				 errdetail_relkind_not_supported(targetrelkind)));
+
+	/* Must be a sequence if specified in EXCEPT sequence list */
+	if (pubrelkind == RELKIND_SEQUENCE && targetrelkind != RELKIND_SEQUENCE)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg(errormsg, relname),
-				 errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
+				 errdetail_relkind_not_supported(targetrelkind)));
 
 	/* Can't be system table */
 	if (IsCatalogRelation(targetrel))
@@ -97,11 +115,15 @@ check_publication_add_relation(PublicationRelInfo *pri)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg(errormsg, relname),
+				 targetrelkind == RELKIND_SEQUENCE ?
+				 errdetail("This operation is not supported for temporary sequences.") :
 				 errdetail("This operation is not supported for temporary tables.")));
 	else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg(errormsg, relname),
+				 targetrelkind == RELKIND_SEQUENCE ?
+				 errdetail("This operation is not supported for unlogged sequences.") :
 				 errdetail("This operation is not supported for unlogged tables.")));
 }
 
@@ -521,7 +543,8 @@ attnumstoint2vector(Bitmapset *attrs)
  */
 ObjectAddress
 publication_add_relation(Oid pubid, PublicationRelInfo *pri,
-						 bool if_not_exists, AlterPublicationStmt *alter_stmt)
+						 bool if_not_exists, AlterPublicationStmt *alter_stmt,
+						 char pubrelkind)
 {
 	Relation	rel;
 	HeapTuple	tup;
@@ -559,7 +582,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
 						RelationGetRelationName(targetrel), pub->name)));
 	}
 
-	check_publication_add_relation(pri);
+	check_publication_add_relation(pri, pubrelkind);
 
 	/* Validate and translate column names into a Bitmapset of attnums. */
 	attnums = pub_collist_validate(pri->relation, pri->columns);
@@ -979,15 +1002,14 @@ GetIncludedPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
 }
 
 /*
- * Gets list of table oids that were specified in the EXCEPT clause for a
- * publication.
- *
- * This should only be used FOR ALL TABLES publications.
+ * Gets list of relation oids that were specified in the EXCEPT clause for a
+ * 'FOR ALL TABLES' or a 'FOR ALL SEQUENCES' publication.
  */
 List *
 GetExcludedPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
 {
-	Assert(GetPublication(pubid)->alltables);
+	Assert(GetPublication(pubid)->alltables ||
+		   GetPublication(pubid)->allsequences);
 
 	return get_publication_relations(pubid, pub_partopt, true);
 }
@@ -1038,8 +1060,9 @@ GetAllTablesPublications(void)
  * root partitioned tables. This is not applicable to FOR ALL SEQUENCES
  * publication.
  *
- * For a FOR ALL TABLES publication, the returned list excludes tables mentioned
- * in the EXCEPT clause.
+ * For a FOR ALL TABLES publication, the returned list excludes tables
+ * mentioned in the EXCEPT clause. For a FOR ALL SEQUENCES publication,
+ * it excludes sequences mentioned in the EXCEPT clause.
  */
 List *
 GetAllPublicationRelations(Oid pubid, char relkind, bool pubviaroot)
@@ -1053,11 +1076,10 @@ GetAllPublicationRelations(Oid pubid, char relkind, bool pubviaroot)
 
 	Assert(!(relkind == RELKIND_SEQUENCE && pubviaroot));
 
-	/* EXCEPT filtering applies only to relations, not sequences */
-	if (relkind == RELKIND_RELATION)
-		exceptlist = GetExcludedPublicationRelations(pubid, pubviaroot ?
-													 PUBLICATION_PART_ROOT :
-													 PUBLICATION_PART_LEAF);
+	/* EXCEPT filtering applies to tables and sequences */
+	exceptlist = GetExcludedPublicationRelations(pubid, pubviaroot ?
+												 PUBLICATION_PART_ROOT :
+												 PUBLICATION_PART_LEAF);
 
 	classRel = table_open(RelationRelationId, AccessShareLock);
 
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 1cae5f10331..e97578ddd75 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -65,7 +65,7 @@ static List *OpenRelationList(List *tables);
 static void CloseRelationList(List *rels);
 static void LockSchemaList(List *schemalist);
 static void PublicationAddRelations(Oid pubid, List *rels, bool if_not_exists,
-									AlterPublicationStmt *stmt);
+									AlterPublicationStmt *stmt, char pubrelkind);
 static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok);
 static void PublicationAddSchemas(Oid pubid, List *schemas, bool if_not_exists,
 								  AlterPublicationStmt *stmt);
@@ -181,7 +181,8 @@ parse_publication_options(ParseState *pstate,
  */
 static void
 ObjectsInPublicationToOids(List *pubobjspec_list, ParseState *pstate,
-						   List **rels, List **excepttbls, List **schemas)
+						   List **rels, List **excepttbls, List **exceptseqs,
+						   List **schemas)
 {
 	ListCell   *cell;
 	PublicationObjSpec *pubobj;
@@ -202,6 +203,10 @@ ObjectsInPublicationToOids(List *pubobjspec_list, ParseState *pstate,
 				pubobj->pubrelation->except = true;
 				*excepttbls = lappend(*excepttbls, pubobj->pubrelation);
 				break;
+			case PUBLICATIONOBJ_EXCEPT_SEQUENCE:
+				pubobj->pubrelation->except = true;
+				*exceptseqs = lappend(*exceptseqs, pubobj->pubrelation);
+				break;
 			case PUBLICATIONOBJ_TABLE:
 				pubobj->pubrelation->except = false;
 				*rels = lappend(*rels, pubobj->pubrelation);
@@ -850,6 +855,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
 	AclResult	aclresult;
 	List	   *relations = NIL;
 	List	   *excepttbls = NIL;
+	List	   *exceptseqs = NIL;
 	List	   *schemaidlist = NIL;
 
 	/* must have CREATE privilege on database */
@@ -936,7 +942,16 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
 
 	/* Associate objects with the publication. */
 	ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
-							   &excepttbls, &schemaidlist);
+							   &excepttbls, &exceptseqs, &schemaidlist);
+
+	/* Process EXCEPT sequence list */
+	if (stmt->for_all_sequences && exceptseqs != NIL)
+	{
+		List	   *rels = OpenRelationList(exceptseqs);
+
+		PublicationAddRelations(puboid, rels, true, NULL, RELKIND_SEQUENCE);
+		CloseRelationList(rels);
+	}
 
 	if (stmt->for_all_tables)
 	{
@@ -946,7 +961,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
 			List	   *rels;
 
 			rels = OpenRelationList(excepttbls);
-			PublicationAddRelations(puboid, rels, true, NULL);
+			PublicationAddRelations(puboid, rels, true, NULL, RELKIND_RELATION);
 			CloseRelationList(rels);
 		}
 
@@ -977,7 +992,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
 									   schemaidlist != NIL,
 									   publish_via_partition_root);
 
-			PublicationAddRelations(puboid, rels, true, NULL);
+			PublicationAddRelations(puboid, rels, true, NULL, RELKIND_RELATION);
 			CloseRelationList(rels);
 		}
 
@@ -1266,7 +1281,7 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
 		CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
 								   pubform->pubviaroot);
 
-		PublicationAddRelations(pubid, rels, false, stmt);
+		PublicationAddRelations(pubid, rels, false, stmt, RELKIND_RELATION);
 	}
 	else if (stmt->action == AP_DropObjects)
 		PublicationDropTables(pubid, rels, false);
@@ -1410,7 +1425,7 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
 		 * Don't bother calculating the difference for adding, we'll catch and
 		 * skip existing ones when doing catalog update.
 		 */
-		PublicationAddRelations(pubid, rels, true, stmt);
+		PublicationAddRelations(pubid, rels, true, stmt, RELKIND_RELATION);
 
 		CloseRelationList(delrels);
 	}
@@ -1684,11 +1699,15 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt)
 	{
 		List	   *relations = NIL;
 		List	   *excepttbls = NIL;
+		List	   *exceptseqs = NIL;
 		List	   *schemaidlist = NIL;
 		Oid			pubid = pubform->oid;
 
 		ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
-								   &excepttbls, &schemaidlist);
+								   &excepttbls, &exceptseqs, &schemaidlist);
+
+		/* EXCEPT clause is not supported with ALTER PUBLICATION */
+		Assert(exceptseqs == NIL);
 
 		CheckAlterPublication(stmt, tup, relations, schemaidlist);
 
@@ -1831,8 +1850,8 @@ RemovePublicationSchemaById(Oid psoid)
 
 /*
  * Open relations specified by a PublicationRelation list.
- * The returned tables are locked in ShareUpdateExclusiveLock mode in order to
- * add them to a publication.
+ * The returned relations are locked in ShareUpdateExclusiveLock mode in order
+ * to add them to a publication.
  */
 static List *
 OpenRelationList(List *tables)
@@ -2032,11 +2051,15 @@ LockSchemaList(List *schemalist)
 }
 
 /*
- * Add listed tables to the publication.
+ * Add listed relations to the publication.
+ *
+ * 'pubrelkind' is the relkind accepted by the publication clause.
+ * The relkind of each relation in 'rels' is checked for compatibility
+ * against it.
  */
 static void
 PublicationAddRelations(Oid pubid, List *rels, bool if_not_exists,
-						AlterPublicationStmt *stmt)
+						AlterPublicationStmt *stmt, char pubrelkind)
 {
 	ListCell   *lc;
 
@@ -2046,12 +2069,12 @@ PublicationAddRelations(Oid pubid, List *rels, bool if_not_exists,
 		Relation	rel = pub_rel->relation;
 		ObjectAddress obj;
 
-		/* Must be owner of the table or superuser. */
+		/* Must be owner of the relation or superuser. */
 		if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
 			aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
 						   RelationGetRelationName(rel));
 
-		obj = publication_add_relation(pubid, pub_rel, if_not_exists, stmt);
+		obj = publication_add_relation(pubid, pub_rel, if_not_exists, stmt, pubrelkind);
 		if (stmt)
 		{
 			EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 157b6d710de..c7a499ab96d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -458,6 +458,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 				vacuum_relation_list opt_vacuum_relation_list
 				drop_option_list pub_obj_list pub_all_obj_type_list
 				pub_except_tbl_list opt_pub_except_tbl_clause
+				pub_except_seq_list opt_pub_except_seq_clause
 
 %type <retclause> returning_clause
 %type <node>	returning_option
@@ -598,6 +599,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <rolespec> auth_ident RoleSpec opt_granted_by
 %type <publicationobjectspec> PublicationObjSpec
 %type <publicationobjectspec> PublicationExceptTblSpec
+%type <publicationobjectspec> PublicationExceptSeqSpec
 %type <publicationallobjectspec> PublicationAllObjSpec
 
 %type <keyword> unreserved_keyword type_func_name_keyword
@@ -11411,6 +11413,11 @@ opt_pub_except_tbl_clause:
 			| /*EMPTY*/									{ $$ = NIL; }
 		;
 
+opt_pub_except_seq_clause:
+			EXCEPT '(' SEQUENCE pub_except_seq_list ')'	{ $$ = $4; }
+			| /*EMPTY*/									{ $$ = NIL; }
+		;
+
 PublicationAllObjSpec:
 				ALL TABLES opt_pub_except_tbl_clause
 					{
@@ -11419,10 +11426,11 @@ PublicationAllObjSpec:
 						$$->except_relations = $3;
 						$$->location = @1;
 					}
-				| ALL SEQUENCES
+				| ALL SEQUENCES opt_pub_except_seq_clause
 					{
 						$$ = makeNode(PublicationAllObjSpec);
 						$$->pubobjtype = PUBLICATION_ALL_SEQUENCES;
+						$$->except_relations = $3;
 						$$->location = @1;
 					}
 					;
@@ -11445,12 +11453,32 @@ PublicationExceptTblSpec:
 				}
 	;
 
+PublicationExceptSeqSpec:
+			 relation_expr
+				{
+					$$ = makeNode(PublicationObjSpec);
+					$$->pubobjtype = PUBLICATIONOBJ_EXCEPT_SEQUENCE;
+					$$->pubrelation = makeNode(PublicationRelation);
+					$$->pubrelation->except = true;
+					$$->pubrelation->relation = $1;
+					$$->location = @1;
+				}
+	;
+
 pub_except_tbl_list: PublicationExceptTblSpec
 					{ $$ = list_make1($1); }
 			| pub_except_tbl_list ',' opt_table PublicationExceptTblSpec
 					{ $$ = lappend($1, $4); }
 	;
 
+pub_except_seq_list: PublicationExceptSeqSpec
+					{ $$ = list_make1($1); }
+			| pub_except_seq_list ',' PublicationExceptSeqSpec
+					{ $$ = lappend($1, $3); }
+			| pub_except_seq_list ',' SEQUENCE PublicationExceptSeqSpec
+					{ $$ = lappend($1, $4); }
+	;
+
 /*****************************************************************************
  *
  * ALTER PUBLICATION name SET ( options )
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d56dcc701ce..ee2331f6345 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4617,18 +4617,22 @@ getPublications(Archive *fout)
 		{
 			NULL, NULL
 		};
+		pubinfo[i].except_sequences = (SimplePtrList)
+		{
+			NULL, NULL
+		};
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(pubinfo[i].dobj), fout);
 
 		/*
-		 * Get the list of tables for publications specified in the EXCEPT
-		 * TABLE clause.
+		 * Get the list of tables and sequences for publications specified in
+		 * the EXCEPT clause.
 		 *
-		 * Although individual table entries in EXCEPT list could be stored in
-		 * PublicationRelInfo, dumpPublicationTable cannot be used to emit
-		 * them, because there is no ALTER PUBLICATION ... ADD command to add
-		 * individual table entries to the EXCEPT list.
+		 * Although individual table/sequence entries in EXCEPT list could be
+		 * stored in PublicationRelInfo, dumpPublicationTable cannot be used
+		 * to emit them, because there is no ALTER PUBLICATION ... ADD command
+		 * to add individual table entries to the EXCEPT list.
 		 *
 		 * Therefore, the approach is to dump the complete EXCEPT list in a
 		 * single CREATE PUBLICATION statement. PublicationInfo is used to
@@ -4642,9 +4646,10 @@ getPublications(Archive *fout)
 
 			resetPQExpBuffer(query);
 			appendPQExpBuffer(query,
-							  "SELECT prrelid\n"
-							  "FROM pg_catalog.pg_publication_rel\n"
-							  "WHERE prpubid = %u AND prexcept",
+							  "SELECT pr.prrelid, pc.relkind\n"
+							  "FROM pg_catalog.pg_publication_rel pr\n"
+							  "JOIN pg_catalog.pg_class pc ON pr.prrelid = pc.oid\n"
+							  "WHERE pr.prpubid = %u AND pr.prexcept",
 							  pubinfo[i].dobj.catId.oid);
 
 			res_tbls = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -4654,14 +4659,21 @@ getPublications(Archive *fout)
 			for (int j = 0; j < ntbls; j++)
 			{
 				Oid			prrelid;
+				char		relkind;
 				TableInfo  *tbinfo;
 
 				prrelid = atooid(PQgetvalue(res_tbls, j, 0));
+				relkind = *PQgetvalue(res_tbls, j, 1);
 
 				tbinfo = findTableByOid(prrelid);
 
 				if (tbinfo != NULL)
-					simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
+				{
+					if (relkind == RELKIND_SEQUENCE)
+						simple_ptr_list_append(&pubinfo[i].except_sequences, tbinfo);
+					else
+						simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
+				}
 			}
 
 			PQclear(res_tbls);
@@ -4721,12 +4733,30 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
 		}
 		if (n_except > 0)
 			appendPQExpBufferChar(query, ')');
+	}
+	if (pubinfo->puballsequences)
+	{
+		int			n_except = 0;
 
-		if (pubinfo->puballsequences)
+		if (pubinfo->puballtables)
 			appendPQExpBufferStr(query, ", ALL SEQUENCES");
+		else
+			appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
+
+		/* Include EXCEPT (SEQUENCE) clause if there are except_sequences. */
+		for (SimplePtrListCell *cell = pubinfo->except_sequences.head; cell; cell = cell->next)
+		{
+			TableInfo  *tbinfo = (TableInfo *) cell->ptr;
+
+			if (++n_except == 1)
+				appendPQExpBufferStr(query, " EXCEPT (");
+			else
+				appendPQExpBufferStr(query, ", ");
+			appendPQExpBuffer(query, "SEQUENCE %s", fmtQualifiedDumpable(tbinfo));
+		}
+		if (n_except > 0)
+			appendPQExpBufferChar(query, ')');
 	}
-	else if (pubinfo->puballsequences)
-		appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
 
 	appendPQExpBufferStr(query, " WITH (publish = '");
 	if (pubinfo->pubinsert)
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 5a6726d8b12..8e869fe791a 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -679,6 +679,7 @@ typedef struct _PublicationInfo
 	bool		pubviaroot;
 	PublishGencolsType pubgencols_type;
 	SimplePtrList except_tables;
+	SimplePtrList except_sequences;
 } PublicationInfo;
 
 /*
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 3bc8e51561d..a3dd4cdb23f 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -3242,6 +3242,26 @@ my %tests = (
 		like => { %full_runs, section_post_data => 1, },
 	},
 
+	'CREATE PUBLICATION pub11' => {
+		create_order => 92,
+		create_sql =>
+		  'CREATE PUBLICATION pub11 FOR ALL SEQUENCES EXCEPT (SEQUENCE public.test_table_col1_seq);',
+		regexp => qr/^
+			\QCREATE PUBLICATION pub11 FOR ALL SEQUENCES EXCEPT (SEQUENCE public.test_table_col1_seq) WITH (publish = 'insert, update, delete, truncate');\E
+			/xm,
+		like => { %full_runs, section_post_data => 1, },
+	},
+
+	'CREATE PUBLICATION pub12' => {
+		create_order => 92,
+		create_sql =>
+		  'CREATE PUBLICATION pub12 FOR ALL TABLES EXCEPT (TABLE dump_test.test_table), ALL SEQUENCES EXCEPT (SEQUENCE public.test_table_col1_seq);',
+		regexp => qr/^
+			\QCREATE PUBLICATION pub12 FOR ALL TABLES EXCEPT (TABLE ONLY dump_test.test_table), ALL SEQUENCES EXCEPT (SEQUENCE public.test_table_col1_seq) WITH (publish = 'insert, update, delete, truncate');\E
+			/xm,
+		like => { %full_runs, section_post_data => 1, },
+	},
+
 	'CREATE SUBSCRIPTION sub1' => {
 		create_order => 50,
 		create_sql => 'CREATE SUBSCRIPTION sub1
@@ -4042,6 +4062,8 @@ my %tests = (
 	},
 
 	'CREATE SEQUENCE test_table_col1_seq' => {
+		create_order => 90,
+		create_sql => 'CREATE SEQUENCE test_table_col1_seq',
 		regexp => qr/^
 			\QCREATE SEQUENCE dump_test.test_table_col1_seq\E
 			\n\s+\QAS integer\E
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index e1449654f96..1f67c310177 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1778,7 +1778,7 @@ describeOneTableDetails(const char *schemaname,
 	{
 		PGresult   *result = NULL;
 		printQueryOpt myopt = pset.popt;
-		char	   *footers[3] = {NULL, NULL, NULL};
+		char	   *footers[4] = {NULL, NULL, NULL, NULL};
 
 		printfPQExpBuffer(&buf, "/* %s */\n", _("Get sequence information"));
 		if (pset.sversion >= 100000)
@@ -1882,11 +1882,16 @@ describeOneTableDetails(const char *schemaname,
 		{
 			printfPQExpBuffer(&buf, "/* %s */\n",
 							  _("Get publications containing this sequence"));
-			appendPQExpBuffer(&buf, "SELECT pubname FROM pg_catalog.pg_publication p"
+			appendPQExpBuffer(&buf, "SELECT p.pubname FROM pg_catalog.pg_publication p"
 							  "\nWHERE p.puballsequences"
 							  "\n AND pg_catalog.pg_relation_is_publishable('%s')"
+							  "\n AND NOT EXISTS (\n"
+							  "     SELECT 1\n"
+							  "     FROM pg_catalog.pg_publication_rel pr\n"
+							  "     WHERE pr.prpubid = p.oid AND\n"
+							  "     pr.prrelid = '%s')"
 							  "\nORDER BY 1",
-							  oid);
+							  oid, oid);
 
 			result = PSQLexec(buf.data);
 			if (result)
@@ -1912,6 +1917,42 @@ describeOneTableDetails(const char *schemaname,
 			}
 		}
 
+		/* Print publications where the sequence is in the EXCEPT clause */
+		if (pset.sversion >= 190000)
+		{
+			printfPQExpBuffer(&buf,
+							  "SELECT p.pubname\n"
+							  "FROM pg_catalog.pg_publication p\n"
+							  "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
+							  "WHERE pr.prrelid = '%s' AND pr.prexcept\n"
+							  "ORDER BY 1;", oid);
+
+			result = PSQLexec(buf.data);
+			if (result)
+			{
+				int			tuples = PQntuples(result);
+
+				if (tuples > 0)
+				{
+					printfPQExpBuffer(&tmpbuf, _("Excluded from publications:"));
+
+					/* Might be an empty set - that's ok */
+					for (i = 0; i < tuples; i++)
+						appendPQExpBuffer(&tmpbuf, "\n    \"%s\"", PQgetvalue(result, i, 0));
+
+					if (footers[0] == NULL)
+						footers[0] = pg_strdup(tmpbuf.data);
+					else if (footers[1] == NULL)
+						footers[1] = pg_strdup(tmpbuf.data);
+					else
+						footers[2] = pg_strdup(tmpbuf.data);
+					resetPQExpBuffer(&tmpbuf);
+				}
+
+				PQclear(result);
+			}
+		}
+
 		if (tableinfo.relpersistence == RELPERSISTENCE_UNLOGGED)
 			printfPQExpBuffer(&title, _("Unlogged sequence \"%s.%s\""),
 							  schemaname, relationname);
@@ -6950,6 +6991,7 @@ describePublications(const char *pattern)
 		char	   *pubid = PQgetvalue(res, i, 0);
 		char	   *pubname = PQgetvalue(res, i, 1);
 		bool		puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
+		bool		puballsequences = strcmp(PQgetvalue(res, i, 4), "t") == 0;
 		printTableOpt myopt = pset.popt.topt;
 
 		initPQExpBuffer(&title);
@@ -6986,7 +7028,7 @@ describePublications(const char *pattern)
 			printTableAddCell(&cont, PQgetvalue(res, i, 10), false, false);
 		printTableAddCell(&cont, PQgetvalue(res, i, 11), false, false);
 
-		if (!puballtables)
+		if (!puballtables && !puballsequences)
 		{
 			/* Get the tables for the specified publication */
 			printfPQExpBuffer(&buf, "/* %s */\n",
@@ -7040,7 +7082,7 @@ describePublications(const char *pattern)
 					goto error_return;
 			}
 		}
-		else
+		if (puballtables)
 		{
 			if (pset.sversion >= 190000)
 			{
@@ -7052,13 +7094,32 @@ describePublications(const char *pattern)
 								  "FROM pg_catalog.pg_class c\n"
 								  "     JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 								  "     JOIN pg_catalog.pg_publication_rel pr ON c.oid = pr.prrelid\n"
-								  "WHERE pr.prpubid = '%s' AND pr.prexcept\n"
+								  "WHERE pr.prpubid = '%s' AND pr.prexcept AND c.relkind IN ('r','p')\n"
 								  "ORDER BY 1", pubid);
 				if (!addFooterToPublicationDesc(&buf, _("Except tables:"),
 												true, &cont))
 					goto error_return;
 			}
 		}
+		if (puballsequences)
+		{
+			if (pset.sversion >= 190000)
+			{
+				/* Get sequences in the EXCEPT clause for this publication */
+				printfPQExpBuffer(&buf, "/* %s */\n",
+								  _("Get sequences excluded by this publication"));
+				printfPQExpBuffer(&buf,
+								  "SELECT n.nspname || '.' || c.relname\n"
+								  "FROM pg_catalog.pg_class c\n"
+								  "     JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
+								  "     JOIN pg_catalog.pg_publication_rel pr ON c.oid = pr.prrelid\n"
+								  "WHERE pr.prpubid = '%s' AND pr.prexcept AND c.relkind = 'S'\n"
+								  "ORDER BY 1", pubid);
+				if (!addFooterToPublicationDesc(&buf, _("Except sequences:"),
+												true, &cont))
+					goto error_return;
+			}
+		}
 
 		printTable(&cont, pset.queryFout, false, pset.logfile);
 		printTableCleanup(&cont);
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index db65d130fcb..96b50ea105c 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -3758,6 +3758,18 @@ match_previous_words(int pattern_id,
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES", "EXCEPT", "(", "TABLE", MatchAnyN) && !ends_with(prev_wd, ','))
 		COMPLETE_WITH(")");
+	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "SEQUENCES"))
+		COMPLETE_WITH("EXCEPT ( SEQUENCE", "WITH (");
+	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "SEQUENCES", "EXCEPT"))
+		COMPLETE_WITH("( SEQUENCE");
+	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "SEQUENCES", "EXCEPT", "("))
+		COMPLETE_WITH("SEQUENCE");
+	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "SEQUENCES", "EXCEPT", "(", "SEQUENCE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
+	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "SEQUENCES", "EXCEPT", "(", "SEQUENCE", MatchAnyN) && ends_with(prev_wd, ','))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
+	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "SEQUENCES", "EXCEPT", "(", "SEQUENCE", MatchAnyN) && !ends_with(prev_wd, ','))
+		COMPLETE_WITH(")");
 	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "TABLES"))
 		COMPLETE_WITH("IN SCHEMA");
 	else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "TABLE", MatchAny) && !ends_with(prev_wd, ','))
diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h
index e4da55d8b71..49c29a87630 100644
--- a/src/include/catalog/pg_publication.h
+++ b/src/include/catalog/pg_publication.h
@@ -200,7 +200,8 @@ extern bool check_and_fetch_column_list(Publication *pub, Oid relid,
 										MemoryContext mcxt, Bitmapset **cols);
 extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri,
 											  bool if_not_exists,
-											  AlterPublicationStmt *alter_stmt);
+											  AlterPublicationStmt *alter_stmt,
+											  char pubrelkind);
 extern Bitmapset *pub_collist_validate(Relation targetrel, List *columns);
 extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid,
 											bool if_not_exists);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 95a74f6bcee..204aea610cb 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -4481,6 +4481,7 @@ typedef enum PublicationObjSpecType
 {
 	PUBLICATIONOBJ_TABLE,		/* A table */
 	PUBLICATIONOBJ_EXCEPT_TABLE,	/* A table in the EXCEPT clause */
+	PUBLICATIONOBJ_EXCEPT_SEQUENCE, /* A sequence in the EXCEPT clause */
 	PUBLICATIONOBJ_TABLES_IN_SCHEMA,	/* All tables in schema */
 	PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA,	/* All tables in first element of
 											 * search_path */
@@ -4509,7 +4510,9 @@ typedef struct PublicationAllObjSpec
 {
 	NodeTag		type;
 	PublicationAllObjType pubobjtype;	/* type of this publication object */
-	List	   *except_relations;	/* tables specified in the EXCEPT clause */
+	List	   *except_relations;	/* depending on the 'pubobjtype', this is
+									 * a list of either tables or sequences
+									 * specified in the EXCEPT clause */
 	ParseLoc	location;		/* token location, or -1 if unknown */
 } PublicationAllObjSpec;
 
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 29e54b214a0..15c30ffeefc 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -458,7 +458,7 @@ Excluded from publications:
 Number of partitions: 1 (Use \d+ to list them.)
 
 CREATE PUBLICATION testpub9 FOR ALL TABLES EXCEPT (TABLE testpub_part1);
-ERROR:  cannot specify relation "public.testpub_part1" in the publication EXCEPT clause
+ERROR:  cannot specify "public.testpub_part1" in the publication EXCEPT (TABLE) clause
 DETAIL:  This operation is not supported for individual partitions.
 CREATE TABLE tab_main (a int) PARTITION BY RANGE(a);
 -- Attaching a partition is not allowed if the partitioned table appears in a
@@ -473,6 +473,7 @@ DROP PUBLICATION testpub8;
 --- Tests for publications with SEQUENCES
 CREATE SEQUENCE regress_pub_seq0;
 CREATE SEQUENCE pub_test.regress_pub_seq1;
+CREATE SEQUENCE regress_pub_seq2;
 -- FOR ALL SEQUENCES
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION regress_pub_forallsequences1 FOR ALL SEQUENCES;
@@ -534,10 +535,64 @@ SELECT pubname, puballtables, puballsequences FROM pg_publication WHERE pubname
  regress_publication_user | t          | t             | t       | f       | f       | f         | stored            | f        | 
 (1 row)
 
-DROP SEQUENCE regress_pub_seq0, pub_test.regress_pub_seq1;
+-- Test ALL SEQUENCES with EXCEPT clause
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION regress_pub_forallsequences3 FOR ALL SEQUENCES EXCEPT (SEQUENCE regress_pub_seq0, pub_test.regress_pub_seq1, SEQUENCE regress_pub_seq2);
+\dRp+ regress_pub_forallsequences3
+                                                   Publication regress_pub_forallsequences3
+          Owner           | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description 
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | f          | t             | t       | t       | t       | t         | none              | f        | 
+Except sequences:
+    "pub_test.regress_pub_seq1"
+    "public.regress_pub_seq0"
+    "public.regress_pub_seq2"
+
+-- Check that the sequence description shows the publications where it is listed
+-- in the EXCEPT clause
+\d+ regress_pub_seq0
+                      Sequence "public.regress_pub_seq0"
+  Type  | Start | Minimum |       Maximum       | Increment | Cycles? | Cache 
+--------+-------+---------+---------------------+-----------+---------+-------
+ bigint |     1 |       1 | 9223372036854775807 |         1 | no      |     1
+Included in publications:
+    "regress_pub_for_allsequences_alltables"
+    "regress_pub_forallsequences1"
+    "regress_pub_forallsequences2"
+Excluded from publications:
+    "regress_pub_forallsequences3"
+
+RESET client_min_messages;
+-- fail - sequence object is specified in EXCEPT table list
+CREATE PUBLICATION regress_pub_forallsequences4 FOR ALL TABLES EXCEPT (TABLE regress_pub_seq0);
+ERROR:  cannot specify "public.regress_pub_seq0" in the publication EXCEPT (TABLE) clause
+DETAIL:  This operation is not supported for sequences.
+-- fail - table object is specified in EXCEPT sequence list
+CREATE TABLE tab_seq(a int);
+CREATE PUBLICATION regress_pub_forallsequences4 FOR ALL SEQUENCES EXCEPT (SEQUENCE tab_seq);
+ERROR:  cannot specify "public.tab_seq" in the publication EXCEPT (SEQUENCE) clause
+DETAIL:  This operation is not supported for tables.
+-- Test combination of ALL SEQUENCES and ALL TABLES with EXCEPT clause
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION regress_pub_for_allsequences_alltables1 FOR ALL TABLES EXCEPT (TABLE testpub_tbl1), ALL SEQUENCES EXCEPT (SEQUENCE regress_pub_seq0);
+\dRp+ regress_pub_for_allsequences_alltables1
+                                             Publication regress_pub_for_allsequences_alltables1
+          Owner           | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description 
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | t          | t             | t       | t       | t       | t         | none              | f        | 
+Except tables:
+    "public.testpub_tbl1"
+Except sequences:
+    "public.regress_pub_seq0"
+
+RESET client_min_messages;
+DROP SEQUENCE regress_pub_seq0, pub_test.regress_pub_seq1, regress_pub_seq2;
 DROP PUBLICATION regress_pub_forallsequences1;
 DROP PUBLICATION regress_pub_forallsequences2;
+DROP PUBLICATION regress_pub_forallsequences3;
 DROP PUBLICATION regress_pub_for_allsequences_alltables;
+DROP PUBLICATION regress_pub_for_allsequences_alltables1;
+DROP TABLE tab_seq;
 -- fail - Specifying ALL TABLES more than once
 CREATE PUBLICATION regress_pub_for_allsequences_alltables FOR ALL SEQUENCES, ALL TABLES, ALL TABLES;
 ERROR:  invalid publication object list
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 041e14a4de6..d472553c7cd 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -223,6 +223,7 @@ DROP PUBLICATION testpub8;
 --- Tests for publications with SEQUENCES
 CREATE SEQUENCE regress_pub_seq0;
 CREATE SEQUENCE pub_test.regress_pub_seq1;
+CREATE SEQUENCE regress_pub_seq2;
 
 -- FOR ALL SEQUENCES
 SET client_min_messages = 'ERROR';
@@ -253,10 +254,35 @@ RESET client_min_messages;
 SELECT pubname, puballtables, puballsequences FROM pg_publication WHERE pubname = 'regress_pub_for_allsequences_alltables';
 \dRp+ regress_pub_for_allsequences_alltables
 
-DROP SEQUENCE regress_pub_seq0, pub_test.regress_pub_seq1;
+-- Test ALL SEQUENCES with EXCEPT clause
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION regress_pub_forallsequences3 FOR ALL SEQUENCES EXCEPT (SEQUENCE regress_pub_seq0, pub_test.regress_pub_seq1, SEQUENCE regress_pub_seq2);
+\dRp+ regress_pub_forallsequences3
+-- Check that the sequence description shows the publications where it is listed
+-- in the EXCEPT clause
+\d+ regress_pub_seq0
+RESET client_min_messages;
+
+-- fail - sequence object is specified in EXCEPT table list
+CREATE PUBLICATION regress_pub_forallsequences4 FOR ALL TABLES EXCEPT (TABLE regress_pub_seq0);
+
+-- fail - table object is specified in EXCEPT sequence list
+CREATE TABLE tab_seq(a int);
+CREATE PUBLICATION regress_pub_forallsequences4 FOR ALL SEQUENCES EXCEPT (SEQUENCE tab_seq);
+
+-- Test combination of ALL SEQUENCES and ALL TABLES with EXCEPT clause
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION regress_pub_for_allsequences_alltables1 FOR ALL TABLES EXCEPT (TABLE testpub_tbl1), ALL SEQUENCES EXCEPT (SEQUENCE regress_pub_seq0);
+\dRp+ regress_pub_for_allsequences_alltables1
+RESET client_min_messages;
+
+DROP SEQUENCE regress_pub_seq0, pub_test.regress_pub_seq1, regress_pub_seq2;
 DROP PUBLICATION regress_pub_forallsequences1;
 DROP PUBLICATION regress_pub_forallsequences2;
+DROP PUBLICATION regress_pub_forallsequences3;
 DROP PUBLICATION regress_pub_for_allsequences_alltables;
+DROP PUBLICATION regress_pub_for_allsequences_alltables1;
+DROP TABLE tab_seq;
 
 -- fail - Specifying ALL TABLES more than once
 CREATE PUBLICATION regress_pub_for_allsequences_alltables FOR ALL SEQUENCES, ALL TABLES, ALL TABLES;
diff --git a/src/test/subscription/t/037_except.pl b/src/test/subscription/t/037_except.pl
index 8c58d282eee..c03c77bb41e 100644
--- a/src/test/subscription/t/037_except.pl
+++ b/src/test/subscription/t/037_except.pl
@@ -282,6 +282,81 @@ $node_subscriber->safe_psql('postgres', 'DROP SUBSCRIPTION tap_sub');
 $node_publisher->safe_psql('postgres', 'DROP PUBLICATION tap_pub1');
 $node_publisher->safe_psql('postgres', 'DROP PUBLICATION tap_pub2');
 
+# ============================================
+# EXCEPT clause test cases for sequences
+# ============================================
+$node_publisher->safe_psql(
+	'postgres', qq (
+	CREATE TABLE seq_test (v BIGINT);
+	CREATE SEQUENCE seq1;
+	CREATE SEQUENCE seq2;
+	INSERT INTO seq_test SELECT nextval('seq1') FROM generate_series(1,100);
+	INSERT INTO seq_test SELECT nextval('seq2') FROM generate_series(1,100);
+	CREATE PUBLICATION tap_pub1 FOR ALL SEQUENCES EXCEPT (SEQUENCE seq1);
+));
+$node_subscriber->safe_psql(
+	'postgres', qq(
+	CREATE SEQUENCE seq1;
+	CREATE SEQUENCE seq2;
+	CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr' PUBLICATION tap_pub1;
+));
+
+# Wait for initial sync to finish
+my $synced_query =
+  "SELECT count(1) = 0 FROM pg_subscription_rel WHERE srsubstate NOT IN ('r');";
+$node_subscriber->poll_query_until('postgres', $synced_query)
+  or die "Timed out while waiting for subscriber to synchronize data";
+
+# Check the initial data on subscriber
+$result = $node_subscriber->safe_psql('postgres',
+	"SELECT last_value, is_called FROM seq1");
+is($result, '1|f', 'sequences in EXCEPT list is excluded');
+
+$result = $node_subscriber->safe_psql('postgres',
+	"SELECT last_value, is_called FROM seq2");
+is($result, '100|t', 'initial test data replicated for seq2');
+
+# ============================================
+# Test when a subscription is subscribing to multiple publications
+# ============================================
+$node_publisher->safe_psql(
+	'postgres', qq(
+	INSERT INTO seq_test SELECT nextval('seq1') FROM generate_series(1,100);
+	INSERT INTO seq_test SELECT nextval('seq2') FROM generate_series(1,100);
+	CREATE PUBLICATION tap_pub2 FOR ALL SEQUENCES EXCEPT (SEQUENCE seq2);
+));
+
+# Subscribe to multiple publications with different EXCEPT sequence list
+$node_subscriber->safe_psql(
+	'postgres', qq(
+	ALTER SUBSCRIPTION tap_sub SET PUBLICATION tap_pub1, tap_pub2;
+	ALTER SUBSCRIPTION tap_sub REFRESH SEQUENCES;
+));
+$synced_query =
+  "SELECT count(1) = 0 FROM pg_subscription_rel WHERE srsubstate NOT IN ('r');";
+$node_subscriber->poll_query_until('postgres', $synced_query)
+  or die "Timed out while waiting for subscriber to synchronize data";
+
+# seq1 is excluded in tap_pub1 but included in tap_pub2, so overall the
+# subscription treats it as included.
+$result = $node_subscriber->safe_psql('postgres',
+	"SELECT last_value, is_called FROM seq1");
+is($result, '200|t',
+	'check replication of a sequence in the EXCEPT clause of one publication but included by another'
+);
+
+# seq2 is excluded in tap_pub2 but included in tap_pub1, so overall the
+# subscription treats it as included.
+$result = $node_subscriber->safe_psql('postgres',
+	"SELECT last_value, is_called FROM seq2");
+is($result, '200|t',
+	'check replication of a sequence in the EXCEPT clause of one publication but included by another'
+);
+
+$node_subscriber->safe_psql('postgres', 'DROP SUBSCRIPTION tap_sub');
+$node_publisher->safe_psql('postgres', 'DROP PUBLICATION tap_pub1');
+$node_publisher->safe_psql('postgres', 'DROP PUBLICATION tap_pub2');
+
 $node_publisher->stop('fast');
 
 done_testing();
-- 
2.34.1

