diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index bc8b859f3001ce4849d29dfa1092f30d900bf059..bbec926434d0c33f529e43ffe00762890b9a6725 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.285 2002/08/18 03:03:25 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.286 2002/08/29 21:02:12 momjian Exp $
  *
  * NOTES
  *
@@ -151,6 +151,18 @@ char	   *VirtualHost;
  */
 int			MaxBackends = DEF_MAXBACKENDS;
 
+/*
+ * 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 none super users is
+ * (MaxBackends - ReservedBackends). Note, existing super user
+ * connections are not taken into account once this lower limit has
+ * been reached, i.e. superuser connections made before the lower limit
+ * is reached always count towards that limit and are not taken from
+ * ReservedBackends.
+ */
+int			ReservedBackends = 2;
+
 
 static char *progname = (char *) NULL;
 
@@ -567,6 +579,12 @@ PostmasterMain(int argc, char *argv[])
 
 	ProcessConfigFile(PGC_POSTMASTER);
 
+	/*
+	 * Force an exit if ReservedBackends is not less than MaxBackends.
+	 */
+	if (ReservedBackends >= MaxBackends)
+		elog(FATAL,"superuser_reserved_connections must be less than max_connections.");
+
 	/*
 	 * Now that we are done processing the postmaster arguments, reset
 	 * getopt(3) library so that it will work correctly in subprocesses.
diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c
index 940ab32b3311af4fa644849c1e4dfcb08e1ab3d8..745a9c068deb25c80237f8bb768a4ff2ef54537a 100644
--- a/src/backend/storage/ipc/sinval.c
+++ b/src/backend/storage/ipc/sinval.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.49 2002/06/20 20:29:35 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.50 2002/08/29 21:02:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -538,3 +538,27 @@ BackendIdGetProc(BackendId procId)
 
 	return NULL;
 }
+
+/*
+ * CountEmptyBackendSlots - count empty slots in backend process table
+ *
+ * Doesn't count since the procState array could be large and we've already
+ * allowed for that by running a freeBackends counter in the SI segment.
+ * Unlike CountActiveBackends() we do not need to interrogate the
+ * backends to determine the free slot count.
+ * Goes for a lock despite being a trival look up in case other backends
+ * are busy starting or exiting since there is scope for confusion.
+ */
+int
+CountEmptyBackendSlots(void)
+{
+	int count;
+
+	LWLockAcquire(SInvalLock, LW_SHARED);
+
+	count = shmInvalBuffer->freeBackends;
+
+	LWLockRelease(SInvalLock);
+
+	return count;
+}
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index c88055c07b51e4e6018b408d6fa38a69945955d8..b4ab1689f942de57ccdde5cc43c6b4cc0486265f 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.47 2002/06/20 20:29:35 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.48 2002/08/29 21:02:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,6 +60,7 @@ SIBufferInit(int maxBackends)
 	segP->maxMsgNum = 0;
 	segP->lastBackend = 0;
 	segP->maxBackends = maxBackends;
+	segP->freeBackends = maxBackends;
 
 	/* The buffer[] array is initially all unused, so we need not fill it */
 
@@ -91,6 +92,13 @@ SIBackendInit(SISeg *segP)
 	int			index;
 	ProcState  *stateP = NULL;
 
+	if (segP->freeBackends == 0)
+	{
+		/* out of procState slots */
+		MyBackendId = InvalidBackendId;
+		return 0;
+	}
+
 	/* Look for a free entry in the procState array */
 	for (index = 0; index < segP->lastBackend; index++)
 	{
@@ -103,18 +111,9 @@ SIBackendInit(SISeg *segP)
 
 	if (stateP == NULL)
 	{
-		if (segP->lastBackend < segP->maxBackends)
-		{
-			stateP = &segP->procState[segP->lastBackend];
-			Assert(stateP->nextMsgNum < 0);
-			segP->lastBackend++;
-		}
-		else
-		{
-			/* out of procState slots */
-			MyBackendId = InvalidBackendId;
-			return 0;
-		}
+		stateP = &segP->procState[segP->lastBackend];
+		Assert(stateP->nextMsgNum < 0);
+		segP->lastBackend++;
 	}
 
 	MyBackendId = (stateP - &segP->procState[0]) + 1;
@@ -123,6 +122,9 @@ SIBackendInit(SISeg *segP)
 	elog(DEBUG1, "SIBackendInit: backend id %d", MyBackendId);
 #endif   /* INVALIDDEBUG */
 
+	/* Reduce free slot count */
+	segP->freeBackends--;
+
 	/* mark myself active, with all extant messages already read */
 	stateP->nextMsgNum = segP->maxMsgNum;
 	stateP->resetState = false;
@@ -166,6 +168,9 @@ CleanupInvalidationState(int status, Datum arg)
 	}
 	segP->lastBackend = i;
 
+	/* Adjust free slot count */
+	segP->freeBackends++;
+
 	LWLockRelease(SInvalLock);
 }
 
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index f36c1d981fa08c6a2721b44f7c47b2a9e7737aa8..b02e371a8182f6739d5645b103dcd29f5dcd36a5 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.110 2002/08/29 07:22:28 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.111 2002/08/29 21:02:12 momjian Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -395,6 +395,16 @@ InitPostgres(const char *dbname, const char *username)
 	/* close the transaction we started above */
 	if (!bootstrap)
 		CommitTransactionCommand();
+
+	/*
+	 * Check a normal user hasn't connected to a superuser reserved slot.
+	 * Do this here since we need the user information and that only happens
+	 * after we've started bringing the shared memory online. So we wait
+	 * until we've registered exit handlers and potentially shut an open
+	 * transaction down for an as safety conscious rejection as possible.
+	 */
+	if (CountEmptyBackendSlots() < ReservedBackends && !superuser())
+		elog(ERROR, "Non-superuser connection limit exceeded");
 }
 
 /*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 5114fcc38f29d5745e0a7067b169eb1f7fac1127..e88882def408f2e5467382e11b8889fee7ddcfeb 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5,7 +5,7 @@
  * command, configuration file, and command line options.
  * See src/backend/utils/misc/README for more information.
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.86 2002/08/29 17:14:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.87 2002/08/29 21:02:12 momjian Exp $
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -537,13 +537,20 @@ static struct config_int
 	/*
 	 * Note: There is some postprocessing done in PostmasterMain() to make
 	 * sure the buffers are at least twice the number of backends, so the
-	 * constraints here are partially unused.
+	 * constraints here are partially unused. Similarly, the superuser
+	 * reserved number is checked to ensure it is less than the max
+	 * backends number.
 	 */
 	{
 		{ "max_connections", PGC_POSTMASTER }, &MaxBackends,
 		DEF_MAXBACKENDS, 1, INT_MAX, NULL, NULL
 	},
 
+	{
+		{ "superuser_reserved_connections", PGC_POSTMASTER }, &ReservedBackends,
+		2, 0, INT_MAX, NULL, NULL
+	},
+
 	{
 		{ "shared_buffers", PGC_POSTMASTER }, &NBuffers,
 		DEF_NBUFFERS, 16, INT_MAX, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c3e065ecdb857776ffba8f1ea65a187392f161dc..11e9caaabcf97e4059a52dece4322352e2c32d8b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -31,6 +31,7 @@
 #ssl = false
 
 #max_connections = 32
+#superuser_reserved_connections = 2
 
 #port = 5432 
 #hostname_lookup = false
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index f2f6f5c67603f61c4fa45ec1b35da83ad21c3fdb..fce4fea4b402af1e3b4816ec0d634917e87b51a9 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.106 2002/06/20 20:29:42 momjian Exp $
+ * $Id: miscadmin.h,v 1.107 2002/08/29 21:02:12 momjian Exp $
  *
  * NOTES
  *	  some of the information in this file should be moved to
@@ -179,6 +179,7 @@ extern bool NetServer;
 extern bool EnableSSL;
 extern bool SilentMode;
 extern int	MaxBackends;
+extern int	ReservedBackends;
 extern int	NBuffers;
 extern int	PostPortNumber;
 extern int	Unix_socket_permissions;
diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h
index 7af8f444470bb1c2dcb09cd632adfe8e1e98be69..1188c68c95add98786b8fbb79b2433e468fe3c19 100644
--- a/src/include/storage/sinval.h
+++ b/src/include/storage/sinval.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinval.h,v 1.28 2002/06/20 20:29:52 momjian Exp $
+ * $Id: sinval.h,v 1.29 2002/08/29 21:02:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,4 +89,6 @@ extern int	CountActiveBackends(void);
 /* Use "struct PGPROC", not PGPROC, to avoid including proc.h here */
 extern struct PGPROC *BackendIdGetProc(BackendId procId);
 
+extern int CountEmptyBackendSlots(void);
+
 #endif   /* SINVAL_H */
diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h
index 3e95342c9f8887aaffc9c26584d47a67bd39152e..39c895026b438f5c0583b515ca27c5b84c99b388 100644
--- a/src/include/storage/sinvaladt.h
+++ b/src/include/storage/sinvaladt.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinvaladt.h,v 1.32 2002/06/20 20:29:52 momjian Exp $
+ * $Id: sinvaladt.h,v 1.33 2002/08/29 21:02:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -85,6 +85,7 @@ typedef struct SISeg
 	int			lastBackend;	/* index of last active procState entry,
 								 * +1 */
 	int			maxBackends;	/* size of procState array */
+	int			freeBackends;	/* number of empty procState slots */
 
 	/*
 	 * Circular buffer holding shared-inval messages