diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 8b380157eef1518d1bd68812c13c9d4c1294fc79..f4bfa5cf6dbe77597a12f9245325fecbcef2cbe1 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.209 2008/05/12 00:00:47 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.210 2008/08/04 18:03:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
 static bool have_createdb_privilege(void);
 static void remove_dbtablespaces(Oid db_id);
 static bool check_db_file_conflict(Oid db_id);
+static int	errdetail_busy_db(int notherbackends, int npreparedxacts);
 
 
 /*
@@ -110,6 +111,8 @@ createdb(const CreatedbStmt *stmt)
 	int			encoding = -1;
 	int			dbconnlimit = -1;
 	int			ctype_encoding;
+	int			notherbackends;
+	int			npreparedxacts;
 	createdb_failure_params fparms;
 
 	/* Extract options from the statement node tree */
@@ -385,11 +388,12 @@ createdb(const CreatedbStmt *stmt)
 	 * potential waiting; we may as well throw an error first if we're gonna
 	 * throw one.
 	 */
-	if (CheckOtherDBBackends(src_dboid))
+	if (CountOtherDBBackends(src_dboid, &notherbackends, &npreparedxacts))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_IN_USE),
 			errmsg("source database \"%s\" is being accessed by other users",
-				   dbtemplate)));
+				   dbtemplate),
+				 errdetail_busy_db(notherbackends, npreparedxacts)));
 
 	/*
 	 * Select an OID for the new database, checking that it doesn't have a
@@ -612,6 +616,8 @@ dropdb(const char *dbname, bool missing_ok)
 	bool		db_istemplate;
 	Relation	pgdbrel;
 	HeapTuple	tup;
+	int			notherbackends;
+	int			npreparedxacts;
 
 	/*
 	 * Look up the target database's OID, and get exclusive lock on it. We
@@ -671,11 +677,12 @@ dropdb(const char *dbname, bool missing_ok)
 	 *
 	 * As in CREATE DATABASE, check this after other error conditions.
 	 */
-	if (CheckOtherDBBackends(db_id))
+	if (CountOtherDBBackends(db_id, &notherbackends, &npreparedxacts))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_IN_USE),
 				 errmsg("database \"%s\" is being accessed by other users",
-						dbname)));
+						dbname),
+				 errdetail_busy_db(notherbackends, npreparedxacts)));
 
 	/*
 	 * Remove the database's tuple from pg_database.
@@ -764,6 +771,8 @@ RenameDatabase(const char *oldname, const char *newname)
 	Oid			db_id;
 	HeapTuple	newtup;
 	Relation	rel;
+	int			notherbackends;
+	int			npreparedxacts;
 
 	/*
 	 * Look up the target database's OID, and get exclusive lock on it. We
@@ -814,11 +823,12 @@ RenameDatabase(const char *oldname, const char *newname)
 	 *
 	 * As in CREATE DATABASE, check this after other error conditions.
 	 */
-	if (CheckOtherDBBackends(db_id))
+	if (CountOtherDBBackends(db_id, &notherbackends, &npreparedxacts))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_IN_USE),
 				 errmsg("database \"%s\" is being accessed by other users",
-						oldname)));
+						oldname),
+				 errdetail_busy_db(notherbackends, npreparedxacts)));
 
 	/* rename */
 	newtup = SearchSysCacheCopy(DATABASEOID,
@@ -1400,6 +1410,29 @@ check_db_file_conflict(Oid db_id)
 	return result;
 }
 
+/*
+ * Issue a suitable errdetail message for a busy database
+ */
+static int
+errdetail_busy_db(int notherbackends, int npreparedxacts)
+{
+	/*
+	 * We don't worry about singular versus plural here, since the English
+	 * rules for that don't translate very well.  But we can at least avoid
+	 * the case of zero items.
+	 */
+	if (notherbackends > 0 && npreparedxacts > 0)
+		errdetail("There are %d other session(s) and %d prepared transaction(s) using the database.",
+				  notherbackends, npreparedxacts);
+	else if (notherbackends > 0)
+		errdetail("There are %d other session(s) using the database.",
+				  notherbackends);
+	else
+		errdetail("There are %d prepared transaction(s) using the database.",
+				  npreparedxacts);
+	return 0;					/* just to keep ereport macro happy */
+}
+
 /*
  * get_database_oid - given a database name, look up the OID
  *
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 0286809d1c4fba135037e2b380d6fca035a1accf..42ed5865d9c80408c90201c3044afba758ccad43 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -23,7 +23,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.45 2008/07/11 02:10:13 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.46 2008/08/04 18:03:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1177,7 +1177,7 @@ CountUserBackends(Oid roleid)
 }
 
 /*
- * CheckOtherDBBackends -- check for other backends running in the given DB
+ * CountOtherDBBackends -- check for other backends running in the given DB
  *
  * If there are other backends in the DB, we will wait a maximum of 5 seconds
  * for them to exit.  Autovacuum backends are encouraged to exit early by
@@ -1187,6 +1187,8 @@ CountUserBackends(Oid roleid)
  * check whether the current backend uses the given DB, if it's important.
  *
  * Returns TRUE if there are (still) other backends in the DB, FALSE if not.
+ * Also, *nbackends and *nprepared are set to the number of other backends
+ * and prepared transactions in the DB, respectively.
  *
  * This function is used to interlock DROP DATABASE and related commands
  * against there being any active backends in the target DB --- dropping the
@@ -1198,19 +1200,24 @@ CountUserBackends(Oid roleid)
  * indefinitely.
  */
 bool
-CheckOtherDBBackends(Oid databaseId)
+CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
 {
 	ProcArrayStruct *arrayP = procArray;
+#define MAXAUTOVACPIDS  10		/* max autovacs to SIGTERM per iteration */
+	int			autovac_pids[MAXAUTOVACPIDS];
 	int			tries;
 
 	/* 50 tries with 100ms sleep between tries makes 5 sec total wait */
 	for (tries = 0; tries < 50; tries++)
 	{
+		int			nautovacs = 0;
 		bool		found = false;
 		int			index;
 
 		CHECK_FOR_INTERRUPTS();
 
+		*nbackends = *nprepared = 0;
+
 		LWLockAcquire(ProcArrayLock, LW_SHARED);
 
 		for (index = 0; index < arrayP->numProcs; index++)
@@ -1224,38 +1231,32 @@ CheckOtherDBBackends(Oid databaseId)
 
 			found = true;
 
-			if (proc->vacuumFlags & PROC_IS_AUTOVACUUM)
-			{
-				/* an autovacuum --- send it SIGTERM before sleeping */
-				int			autopid = proc->pid;
-
-				/*
-				 * It's a bit awkward to release ProcArrayLock within the
-				 * loop, but we'd probably better do so before issuing kill().
-				 * We have no idea what might block kill() inside the
-				 * kernel...
-				 */
-				LWLockRelease(ProcArrayLock);
-
-				(void) kill(autopid, SIGTERM);	/* ignore any error */
-
-				break;
-			}
+			if (proc->pid == 0)
+				(*nprepared)++;
 			else
 			{
-				LWLockRelease(ProcArrayLock);
-				break;
+				(*nbackends)++;
+				if ((proc->vacuumFlags & PROC_IS_AUTOVACUUM) &&
+					nautovacs < MAXAUTOVACPIDS)
+					autovac_pids[nautovacs++] = proc->pid;
 			}
 		}
 
-		/* if found is set, we released the lock within the loop body */
+		LWLockRelease(ProcArrayLock);
+
 		if (!found)
-		{
-			LWLockRelease(ProcArrayLock);
 			return false;		/* no conflicting backends, so done */
-		}
 
-		/* else sleep and try again */
+		/*
+		 * Send SIGTERM to any conflicting autovacuums before sleeping.
+		 * We postpone this step until after the loop because we don't
+		 * want to hold ProcArrayLock while issuing kill().
+		 * We have no idea what might block kill() inside the kernel...
+		 */
+		for (index = 0; index < nautovacs; index++)
+			(void) kill(autovac_pids[index], SIGTERM);	/* ignore any error */
+
+		/* sleep, then try again */
 		pg_usleep(100 * 1000L); /* 100ms */
 	}
 
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index ea0aa999441843a2afd6c29ff1630cbb113a2ac6..4f412c5f1ba0d815d4a0f5f7efbfa84c385904d7 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.22 2008/05/12 20:02:02 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.23 2008/08/04 18:03:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,7 +44,8 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
 extern int	CountActiveBackends(void);
 extern int	CountDBBackends(Oid databaseid);
 extern int	CountUserBackends(Oid roleid);
-extern bool CheckOtherDBBackends(Oid databaseId);
+extern bool CountOtherDBBackends(Oid databaseId,
+								 int *nbackends, int *nprepared);
 
 extern void XidCacheRemoveRunningXids(TransactionId xid,
 						  int nxids, const TransactionId *xids,