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 - In order to be able to copy the initial table or sequence data, the role - used for the replication connection must have the SELECT - 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 + SELECT privilege on a published table or sequence (or be + a superuser). @@ -2611,6 +2612,13 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER security within the database is of no concern. + + When synchronizing sequences with + run_as_owner = true, the subscription owner similarly + needs UPDATE privilege on the target sequence and does + not need privileges to SET ROLE to the sequence owner. + + 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)