diff --git i/src/backend/replication/logical/launcher.c w/src/backend/replication/logical/launcher.c
index 313e31ff2e3..e680c5a6966 100644
--- i/src/backend/replication/logical/launcher.c
+++ w/src/backend/replication/logical/launcher.c
@@ -67,7 +67,8 @@ typedef struct LogicalRepCtxStruct
 	dshash_table_handle last_start_dsh;
 
 	/* Background workers. */
-	LogicalRepWorker workers[FLEXIBLE_ARRAY_MEMBER];
+	int		nworkers;
+	LogicalRepWorker workers[FLEXIBLE_ARRAY_MEMBER] pg_attribute_counted_by(nworkers);
 } LogicalRepCtxStruct;
 
 static LogicalRepCtxStruct *LogicalRepCtx;
@@ -276,7 +277,7 @@ logicalrep_worker_find(LogicalRepWorkerType wtype, Oid subid, Oid relid,
 	Assert(LWLockHeldByMe(LogicalRepWorkerLock));
 
 	/* Search for an attached worker that matches the specified criteria. */
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -311,7 +312,7 @@ logicalrep_workers_find(Oid subid, bool only_running, bool acquire_lock)
 	Assert(LWLockHeldByMe(LogicalRepWorkerLock));
 
 	/* Search for attached worker for a given subscription id. */
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -380,7 +381,7 @@ logicalrep_worker_launch(LogicalRepWorkerType wtype,
 
 retry:
 	/* Find unused worker slot. */
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -405,7 +406,7 @@ logicalrep_worker_launch(LogicalRepWorkerType wtype,
 	{
 		bool		did_cleanup = false;
 
-		for (i = 0; i < max_logical_replication_workers; i++)
+		for (i = 0; i < LogicalRepCtx->nworkers; i++)
 		{
 			LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -697,7 +698,7 @@ logicalrep_pa_worker_stop(ParallelApplyWorkerInfo *winfo)
 	slot_no = winfo->shared->logicalrep_worker_slot_no;
 	SpinLockRelease(&winfo->shared->mutex);
 
-	Assert(slot_no >= 0 && slot_no < max_logical_replication_workers);
+	Assert(slot_no >= 0 && slot_no < LogicalRepCtx->nworkers);
 
 	/*
 	 * Detach from the error_mq_handle for the parallel apply worker before
@@ -769,7 +770,7 @@ logicalrep_worker_attach(int slot)
 	/* Block concurrent access. */
 	LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE);
 
-	Assert(slot >= 0 && slot < max_logical_replication_workers);
+	Assert(slot >= 0 && slot < LogicalRepCtx->nworkers);
 	MyLogicalRepWorker = &LogicalRepCtx->workers[slot];
 
 	if (!MyLogicalRepWorker->in_use)
@@ -942,7 +943,7 @@ logicalrep_sync_worker_count(Oid subid)
 	Assert(LWLockHeldByMe(LogicalRepWorkerLock));
 
 	/* Search for attached worker for a given subscription id. */
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -969,7 +970,7 @@ logicalrep_pa_worker_count(Oid subid)
 	 * Scan all attached parallel apply workers, only counting those which
 	 * have the given subscription id.
 	 */
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -1049,9 +1050,10 @@ ApplyLauncherShmemInit(void *arg)
 
 	LogicalRepCtx->last_start_dsa = DSA_HANDLE_INVALID;
 	LogicalRepCtx->last_start_dsh = DSHASH_HANDLE_INVALID;
+	LogicalRepCtx->nworkers = max_logical_replication_workers;
 
 	/* Initialize memory and spin locks for each worker slot. */
-	for (slot = 0; slot < max_logical_replication_workers; slot++)
+	for (slot = 0; slot < LogicalRepCtx->nworkers; slot++)
 	{
 		LogicalRepWorker *worker = &LogicalRepCtx->workers[slot];
 
@@ -1602,7 +1604,7 @@ GetLeaderApplyWorkerPid(pid_t pid)
 
 	LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
 
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		LogicalRepWorker *w = &LogicalRepCtx->workers[i];
 
@@ -1634,7 +1636,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 	/* Make sure we get consistent view of the workers. */
 	LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
 
-	for (i = 0; i < max_logical_replication_workers; i++)
+	for (i = 0; i < LogicalRepCtx->nworkers; i++)
 	{
 		/* for each row */
 		Datum		values[PG_STAT_GET_SUBSCRIPTION_COLS] = {0};
