*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 162,175 **** char	   *ListenAddresses;
  
  /*
   * ReservedBackends is the number of backends reserved for superuser use.
!  * This number is taken out of the pool size given by MaxBackends so
!  * number of backend slots available to non-superusers is
!  * (MaxBackends - ReservedBackends).  Note what this really means is
!  * "if there are <= ReservedBackends connections available, only superusers
!  * can make new connections" --- pre-existing superuser connections don't
!  * count against the limit.
   */
! int			ReservedBackends;
  
  /* The socket(s) we're listening to. */
  #define MAXLISTEN	64
--- 162,177 ----
  
  /*
   * ReservedBackends is the number of backends reserved for superuser use.
!  * This number is ReservedConnections + max_wal_senders (it is computed by
!  * the GUC assign hooks for those variables) and taken out of the pool size
!  * given by MaxBackends so number of backend slots available to
!  * non-superusers is (MaxBackends - ReservedBackends).  Note what this
!  * really means is "if there are <= ReservedBackends connections available,
!  * only superusers can make new connections" --- pre-existing superuser
!  * connections don't count against the limit.
   */
! int			ReservedBackends = 3;
! int			ReservedConnections = 3;
  
  /* The socket(s) we're listening to. */
  #define MAXLISTEN	64
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
***************
*** 142,149 **** ProcGlobalSemas(void)
   *	  running out when trying to start another backend is a common failure.
   *	  So, now we grab enough semaphores to support the desired max number
   *	  of backends immediately at initialization --- if the sysadmin has set
!  *	  MaxConnections or autovacuum_max_workers higher than his kernel will
!  *	  support, he'll find out sooner rather than later.
   *
   *	  Another reason for creating semaphores here is that the semaphore
   *	  implementation typically requires us to create semaphores in the
--- 142,149 ----
   *	  running out when trying to start another backend is a common failure.
   *	  So, now we grab enough semaphores to support the desired max number
   *	  of backends immediately at initialization --- if the sysadmin has set
!  *	  MaxConnections, autovacuum_max_workers, or max_wal_senders higher
!  *	  than his kernel will support, he'll find out sooner rather than later.
   *
   *	  Another reason for creating semaphores here is that the semaphore
   *	  implementation typically requires us to create semaphores in the
***************
*** 158,163 **** InitProcGlobal(void)
--- 158,164 ----
  {
  	PGPROC	   *procs;
  	int			i;
+ 	int			numconn;
  	bool		found;
  
  	/* Create the ProcGlobal shared structure */
***************
*** 185,197 **** InitProcGlobal(void)
  	/*
  	 * Pre-create the PGPROC structures and create a semaphore for each.
  	 */
! 	procs = (PGPROC *) ShmemAlloc((MaxConnections) * sizeof(PGPROC));
  	if (!procs)
  		ereport(FATAL,
  				(errcode(ERRCODE_OUT_OF_MEMORY),
  				 errmsg("out of shared memory")));
! 	MemSet(procs, 0, MaxConnections * sizeof(PGPROC));
! 	for (i = 0; i < MaxConnections; i++)
  	{
  		PGSemaphoreCreate(&(procs[i].sem));
  		procs[i].links.next = (SHM_QUEUE *) ProcGlobal->freeProcs;
--- 186,199 ----
  	/*
  	 * Pre-create the PGPROC structures and create a semaphore for each.
  	 */
! 	numconn = MaxConnections + max_wal_senders;
! 	procs = (PGPROC *) ShmemAlloc((numconn) * sizeof(PGPROC));
  	if (!procs)
  		ereport(FATAL,
  				(errcode(ERRCODE_OUT_OF_MEMORY),
  				 errmsg("out of shared memory")));
! 	MemSet(procs, 0, numconn * sizeof(PGPROC));
! 	for (i = 0; i < numconn; i++)
  	{
  		PGSemaphoreCreate(&(procs[i].sem));
  		procs[i].links.next = (SHM_QUEUE *) ProcGlobal->freeProcs;
*** a/src/backend/utils/init/globals.c
--- b/src/backend/utils/init/globals.c
***************
*** 100,107 **** int			maintenance_work_mem = 16384;
  
  /*
   * Primary determinants of sizes of shared-memory structures.  MaxBackends is
!  * MaxConnections + autovacuum_max_workers + 1 (it is computed by the GUC
!  * assign hooks for those variables):
   */
  int			NBuffers = 1000;
  int			MaxBackends = 100;
--- 100,107 ----
  
  /*
   * Primary determinants of sizes of shared-memory structures.  MaxBackends is
!  * MaxConnections + autovacuum_max_workers + 1 + max_wal_senders (it is
!  * computed by the GUC assign hooks for those variables):
   */
  int			NBuffers = 1000;
  int			MaxBackends = 100;
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 172,178 **** static const char *show_tcp_keepalives_idle(void);
--- 172,180 ----
  static const char *show_tcp_keepalives_interval(void);
  static const char *show_tcp_keepalives_count(void);
  static bool assign_maxconnections(int newval, bool doit, GucSource source);
+ static bool assign_reserved_connections(int newval, bool doit, GucSource source);
  static bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source);
+ static bool assign_max_wal_senders(int newval, bool doit, GucSource source);
  static bool assign_effective_io_concurrency(int newval, bool doit, GucSource source);
  static const char *assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source);
  static const char *assign_application_name(const char *newval, bool doit, GucSource source);
***************
*** 1361,1367 **** static struct config_int ConfigureNamesInt[] =
  	 * Note: MaxBackends is limited to INT_MAX/4 because some places compute
  	 * 4*MaxBackends without any overflow check.  This check is made in
  	 * assign_maxconnections, since MaxBackends is computed as MaxConnections
! 	 * plus autovacuum_max_workers plus one (for the autovacuum launcher).
  	 *
  	 * Likewise we have to limit NBuffers to INT_MAX/2.
  	 *
--- 1363,1370 ----
  	 * Note: MaxBackends is limited to INT_MAX/4 because some places compute
  	 * 4*MaxBackends without any overflow check.  This check is made in
  	 * assign_maxconnections, since MaxBackends is computed as MaxConnections
! 	 * plus autovacuum_max_workers plus one (for the autovacuum launcher)
! 	 * plus max_wal_senders.
  	 *
  	 * Likewise we have to limit NBuffers to INT_MAX/2.
  	 *
***************
*** 1390,1397 **** static struct config_int ConfigureNamesInt[] =
  			gettext_noop("Sets the number of connection slots reserved for superusers."),
  			NULL
  		},
! 		&ReservedBackends,
! 		3, 0, INT_MAX / 4, NULL, NULL
  	},
  
  	{
--- 1393,1400 ----
  			gettext_noop("Sets the number of connection slots reserved for superusers."),
  			NULL
  		},
! 		&ReservedConnections,
! 		3, 0, INT_MAX / 4, assign_reserved_connections, NULL
  	},
  
  	{
***************
*** 1706,1712 **** static struct config_int ConfigureNamesInt[] =
  			NULL
  		},
  		&max_wal_senders,
! 		0, 0, INT_MAX / 4, NULL, NULL
  	},
  
  	{
--- 1709,1715 ----
  			NULL
  		},
  		&max_wal_senders,
! 		0, 0, INT_MAX / 4, assign_max_wal_senders, NULL
  	},
  
  	{
***************
*** 7819,7829 **** show_tcp_keepalives_count(void)
  static bool
  assign_maxconnections(int newval, bool doit, GucSource source)
  {
! 	if (newval + autovacuum_max_workers + 1 > INT_MAX / 4)
  		return false;
  
  	if (doit)
! 		MaxBackends = newval + autovacuum_max_workers + 1;
  
  	return true;
  }
--- 7822,7844 ----
  static bool
  assign_maxconnections(int newval, bool doit, GucSource source)
  {
! 	if (newval + autovacuum_max_workers + 1 + max_wal_senders > INT_MAX / 4)
  		return false;
  
  	if (doit)
! 		MaxBackends = newval + autovacuum_max_workers + 1 + max_wal_senders;
! 
! 	return true;
! }
! 
! static bool
! assign_reserved_connections(int newval, bool doit, GucSource source)
! {
! 	if (newval + max_wal_senders > INT_MAX / 4)
! 		return false;
! 
! 	if (doit)
! 		ReservedBackends = newval + max_wal_senders;
  
  	return true;
  }
***************
*** 7831,7841 **** assign_maxconnections(int newval, bool doit, GucSource source)
  static bool
  assign_autovacuum_max_workers(int newval, bool doit, GucSource source)
  {
! 	if (MaxConnections + newval + 1 > INT_MAX / 4)
  		return false;
  
  	if (doit)
! 		MaxBackends = MaxConnections + newval + 1;
  
  	return true;
  }
--- 7846,7872 ----
  static bool
  assign_autovacuum_max_workers(int newval, bool doit, GucSource source)
  {
! 	if (MaxConnections + newval + 1 + max_wal_senders > INT_MAX / 4)
  		return false;
  
  	if (doit)
! 		MaxBackends = MaxConnections + newval + 1 + max_wal_senders;
! 
! 	return true;
! }
! 
! static bool
! assign_max_wal_senders(int newval, bool doit, GucSource source)
! {
! 	if (MaxConnections + autovacuum_max_workers + 1 + newval > INT_MAX / 4 ||
! 		ReservedConnections + newval > INT_MAX / 4)
! 		return false;
! 
! 	if (doit)
! 	{
! 		MaxBackends = MaxConnections + autovacuum_max_workers + 1 + newval;
! 		ReservedBackends = ReservedConnections + newval;
! 	}
  
  	return true;
  }
*** a/src/include/postmaster/postmaster.h
--- b/src/include/postmaster/postmaster.h
***************
*** 17,22 ****
--- 17,23 ----
  extern bool EnableSSL;
  extern bool SilentMode;
  extern int	ReservedBackends;
+ extern int	ReservedConnections;
  extern int	PostPortNumber;
  extern int	Unix_socket_permissions;
  extern char *Unix_socket_group;
