From f71d95fed5c4c4c1a0492c616c153e1e66555772 Mon Sep 17 00:00:00 2001
From: Fujii Masao <fujii@postgresql.org>
Date: Wed, 1 Jul 2026 23:56:10 +0900
Subject: [PATCH v2] Add hints for sequence synchronization permission warnings

Sequence synchronization reports insufficient privileges on publisher
and subscriber sequences, but the warnings do not indicate which role
needs which privilege. This makes common configuration mistakes harder
to diagnose.

Add HINT messages for these warnings. Publisher-side warnings suggest
granting SELECT to the role used for the replication connection.
Subscriber-side warnings suggest granting UPDATE to the subscription
owner when run_as_owner is enabled. Otherwise, the worker runs as the
sequence owner, so no useful GRANT hint can be provided.
---
 doc/src/sgml/logical-replication.sgml         | 14 ++++++++---
 .../replication/logical/sequencesync.c        | 23 +++++++++++++++++--
 2 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 5befefd9c5a..d7d75b7c9a5 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -2542,9 +2542,10 @@ CONTEXT:  processing remote data for replication origin "pg_16395" during "INSER
   </para>
 
   <para>
-   In order to be able to copy the initial table or sequence data, the role
-   used for the replication connection must have the <literal>SELECT</literal>
-   privilege on a published table or sequence (or be a superuser).
+   In order to be able to copy the initial table data or synchronize
+   sequences, the role used for the replication connection must have the
+   <literal>SELECT</literal> privilege on a published table or sequence (or be
+   a superuser).
   </para>
 
   <para>
@@ -2611,6 +2612,13 @@ CONTEXT:  processing remote data for replication origin "pg_16395" during "INSER
    security within the database is of no concern.
   </para>
 
+  <para>
+   When synchronizing sequences with
+   <literal>run_as_owner = true</literal>, the subscription owner similarly
+   needs <literal>UPDATE</literal> privilege on the target sequence and does
+   not need privileges to <literal>SET ROLE</literal> to the sequence owner.
+  </para>
+
   <para>
    On the publisher, privileges are only checked once at the start of a
    replication connection and are not re-checked as each change record is read.
diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c
index f47f962c7db..770fa5de10b 100644
--- a/src/backend/replication/logical/sequencesync.c
+++ b/src/backend/replication/logical/sequencesync.c
@@ -201,12 +201,26 @@ report_sequence_errors(List *mismatched_seqs_idx,
 	if (sub_insuffperm_seqs_idx)
 	{
 		get_sequences_string(sub_insuffperm_seqs_idx, &seqstr);
+
+		/*
+		 * With run_as_owner enabled, sequence synchronization runs as the
+		 * subscription owner, so a missing UPDATE privilege should be granted
+		 * to that role. Otherwise, the worker switches to the sequence owner
+		 * before checking privileges, so no useful GRANT hint can be
+		 * provided.
+		 */
 		ereport(WARNING,
 				errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				errmsg_plural("insufficient privileges on subscriber sequence (%s)",
 							  "insufficient privileges on subscriber sequences (%s)",
 							  list_length(sub_insuffperm_seqs_idx),
-							  seqstr.data));
+							  seqstr.data),
+				MySubscription->runasowner ?
+				errhint_plural("Grant UPDATE on the sequence to the subscription "
+							   "owner on the subscriber.",
+							   "Grant UPDATE on the sequences to the subscription "
+							   "owner on the subscriber.",
+							   list_length(sub_insuffperm_seqs_idx)) : 0);
 	}
 
 	if (pub_insuffperm_seqs_idx)
@@ -217,7 +231,12 @@ report_sequence_errors(List *mismatched_seqs_idx,
 				errmsg_plural("insufficient privileges on publisher sequence (%s)",
 							  "insufficient privileges on publisher sequences (%s)",
 							  list_length(pub_insuffperm_seqs_idx),
-							  seqstr.data));
+							  seqstr.data),
+				errhint_plural("Grant SELECT on the sequence to the role used for "
+							   "the replication connection on the publisher.",
+							   "Grant SELECT on the sequences to the role used for "
+							   "the replication connection on the publisher.",
+							   list_length(pub_insuffperm_seqs_idx)));
 	}
 
 	if (missing_seqs_idx)
-- 
2.53.0

