diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
new file mode 100644
index 133143d..fe7eed9
*** a/src/backend/access/transam/xlogfuncs.c
--- b/src/backend/access/transam/xlogfuncs.c
***************
*** 27,32 ****
--- 27,33 ----
  #include "miscadmin.h"
  #include "replication/walreceiver.h"
  #include "storage/smgr.h"
+ #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/numeric.h"
  #include "utils/guc.h"
*************** pg_start_backup(PG_FUNCTION_ARGS)
*** 54,63 ****
  
  	backupidstr = text_to_cstring(backupid);
  
! 	if (!superuser() && !has_rolreplication(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 		   errmsg("must be superuser or replication role to run a backup")));
  
  	startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
  
--- 55,65 ----
  
  	backupidstr = text_to_cstring(backupid);
  
! 	if (!has_replication_privilege(GetUserId())
! 		&& !has_backup_privilege(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser, replication role or backup role to run a backup")));
  
  	startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
  
*************** pg_stop_backup(PG_FUNCTION_ARGS)
*** 82,91 ****
  {
  	XLogRecPtr	stoppoint;
  
! 	if (!superuser() && !has_rolreplication(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 		 (errmsg("must be superuser or replication role to run a backup"))));
  
  	stoppoint = do_pg_stop_backup(NULL, true, NULL);
  
--- 84,94 ----
  {
  	XLogRecPtr	stoppoint;
  
! 	if (!has_replication_privilege(GetUserId())
! 		&& !has_backup_privilege(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser, replication role or backup role to run a backup")));
  
  	stoppoint = do_pg_stop_backup(NULL, true, NULL);
  
*************** pg_switch_xlog(PG_FUNCTION_ARGS)
*** 100,109 ****
  {
  	XLogRecPtr	switchpoint;
  
! 	if (!superuser())
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 			 (errmsg("must be superuser to switch transaction log files"))));
  
  	if (RecoveryInProgress())
  		ereport(ERROR,
--- 103,112 ----
  {
  	XLogRecPtr	switchpoint;
  
! 	if (!has_backup_privilege(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser or backup role to switch transaction log files")));
  
  	if (RecoveryInProgress())
  		ereport(ERROR,
*************** pg_create_restore_point(PG_FUNCTION_ARGS
*** 129,138 ****
  	char	   *restore_name_str;
  	XLogRecPtr	restorepoint;
  
! 	if (!superuser())
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 (errmsg("must be superuser to create a restore point"))));
  
  	if (RecoveryInProgress())
  		ereport(ERROR,
--- 132,141 ----
  	char	   *restore_name_str;
  	XLogRecPtr	restorepoint;
  
! 	if (!has_backup_privilege(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 (errmsg("must be superuser or backup role to create a restore point"))));
  
  	if (RecoveryInProgress())
  		ereport(ERROR,
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
new file mode 100644
index d30612c..64cf9f6
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** static AclMode restrict_and_check_grant(
*** 143,148 ****
--- 143,149 ----
  						 AttrNumber att_number, const char *colname);
  static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
  		   Oid roleid, AclMode mask, AclMaskHow how);
+ static bool has_catupdate_privilege(Oid roleid);
  
  
  #ifdef ACLDEBUG
*************** aclcheck_error_type(AclResult aclerr, Oi
*** 3425,3431 ****
  
  /* Check if given user has rolcatupdate privilege according to pg_authid */
  static bool
! has_rolcatupdate(Oid roleid)
  {
  	bool		rolcatupdate;
  	HeapTuple	tuple;
--- 3426,3432 ----
  
  /* Check if given user has rolcatupdate privilege according to pg_authid */
  static bool
! has_catupdate_privilege(Oid roleid)
  {
  	bool		rolcatupdate;
  	HeapTuple	tuple;
*************** pg_class_aclmask(Oid table_oid, Oid role
*** 3630,3636 ****
  	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
  		IsSystemClass(table_oid, classForm) &&
  		classForm->relkind != RELKIND_VIEW &&
! 		!has_rolcatupdate(roleid) &&
  		!allowSystemTableMods)
  	{
  #ifdef ACLDEBUG
--- 3631,3637 ----
  	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
  		IsSystemClass(table_oid, classForm) &&
  		classForm->relkind != RELKIND_VIEW &&
! 		!has_catupdate_privilege(roleid) &&
  		!allowSystemTableMods)
  	{
  #ifdef ACLDEBUG
*************** has_createrole_privilege(Oid roleid)
*** 5080,5085 ****
--- 5081,5111 ----
  	return result;
  }
  
+ /*
+  * Check whether specified role has REPLICATION privilege (or is a superuser)
+  */
+ bool
+ has_replication_privilege(Oid roleid)
+ {
+ 	bool		result = false;
+ 	HeapTuple	utup;
+ 
+ 	/* Superusers bypass all permission checking. */
+ 	if (superuser_arg(roleid))
+ 		return true;
+ 
+ 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ 	if (HeapTupleIsValid(utup))
+ 	{
+ 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
+ 		ReleaseSysCache(utup);
+ 	}
+ 	return result;
+ }
+ 
+ /*
+  * Check whether specified role has BYPASSRLS privilege (or is a superuser)
+  */
  bool
  has_bypassrls_privilege(Oid roleid)
  {
*************** has_bypassrls_privilege(Oid roleid)
*** 5097,5102 ****
--- 5123,5217 ----
  		ReleaseSysCache(utup);
  	}
  	return result;
+ }
+ 
+ /*
+  * Check whether specified role has BACKUP privilege (or is a superuser)
+  */
+ bool
+ has_backup_privilege(Oid roleid)
+ {
+ 	bool		result = false;
+ 	HeapTuple	utup;
+ 
+ 	/* Superusers bypass all permission checking. */
+ 	if (superuser_arg(roleid))
+ 		return true;
+ 
+ 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ 	if (HeapTupleIsValid(utup))
+ 	{
+ 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolbackup;
+ 		ReleaseSysCache(utup);
+ 	}
+ 
+ 	return result;
+ }
+ 
+ /*
+  * Check whether specified role has LOGROTATE privilege (or is a superuser)
+  */
+ bool
+ has_logrotate_privilege(Oid roleid)
+ {
+ 	bool		result = false;
+ 	HeapTuple	utup;
+ 
+ 	/* Superusers bypass all permission checking. */
+ 	if (superuser_arg(roleid))
+ 		return true;
+ 
+ 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ 	if (HeapTupleIsValid(utup))
+ 	{
+ 		result = ((Form_pg_authid) GETSTRUCT(utup))->rollogrotate;
+ 		ReleaseSysCache(utup);
+ 	}
+ 	return result;
+ }
+ 
+ /*
+  * Check whether specified role has MONITOR privilege (or is a superuser)
+  */
+ bool
+ has_monitor_privilege(Oid roleid)
+ {
+ 	bool		result = false;
+ 	HeapTuple	utup;
+ 
+ 	/* Superusers bypass all permission checking. */
+ 	if (superuser_arg(roleid))
+ 		return true;
+ 
+ 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ 	if (HeapTupleIsValid(utup))
+ 	{
+ 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolmonitor;
+ 		ReleaseSysCache(utup);
+ 	}
+ 	return result;
+ }
+ 
+ /*
+  * Check whether specified role has PROCSIGNAL privilege (or is a superuser)
+  */
+ bool
+ has_procsignal_privilege(Oid roleid)
+ {
+ 	bool		result = false;
+ 	HeapTuple	utup;
+ 
+ 	/* Superusers bypass all permission checking. */
+ 	if (superuser_arg(roleid))
+ 		return true;
+ 
+ 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ 	if (HeapTupleIsValid(utup))
+ 	{
+ 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolprocsignal;
+ 		ReleaseSysCache(utup);
+ 	}
+ 	return result;
  }
  
  /*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
new file mode 100644
index c9a9baf..ed89b23
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
*************** AlterObjectOwner_internal(Relation rel,
*** 807,852 ****
  		bool	   *nulls;
  		bool	   *replaces;
  
! 		/* Superusers can bypass permission checks */
! 		if (!superuser())
  		{
! 			AclObjectKind aclkind = get_object_aclkind(classId);
  
! 			/* must be owner */
! 			if (!has_privs_of_role(GetUserId(), old_ownerId))
  			{
! 				char	   *objname;
! 				char		namebuf[NAMEDATALEN];
! 
! 				if (Anum_name != InvalidAttrNumber)
! 				{
! 					datum = heap_getattr(oldtup, Anum_name,
! 										 RelationGetDescr(rel), &isnull);
! 					Assert(!isnull);
! 					objname = NameStr(*DatumGetName(datum));
! 				}
! 				else
! 				{
! 					snprintf(namebuf, sizeof(namebuf), "%u",
! 							 HeapTupleGetOid(oldtup));
! 					objname = namebuf;
! 				}
! 				aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
  			}
! 			/* Must be able to become new owner */
! 			check_is_member_of_role(GetUserId(), new_ownerId);
! 
! 			/* New owner must have CREATE privilege on namespace */
! 			if (OidIsValid(namespaceId))
  			{
! 				AclResult	aclresult;
! 
! 				aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
! 												  ACL_CREATE);
! 				if (aclresult != ACLCHECK_OK)
! 					aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 								   get_namespace_name(namespaceId));
  			}
  		}
  
  		/* Build a modified tuple */
--- 807,848 ----
  		bool	   *nulls;
  		bool	   *replaces;
  
! 		AclObjectKind aclkind = get_object_aclkind(classId);
! 
! 		/* must be owner */
! 		if (!has_privs_of_role(GetUserId(), old_ownerId))
  		{
! 			char	   *objname;
! 			char		namebuf[NAMEDATALEN];
  
! 			if (Anum_name != InvalidAttrNumber)
  			{
! 				datum = heap_getattr(oldtup, Anum_name,
! 									 RelationGetDescr(rel), &isnull);
! 				Assert(!isnull);
! 				objname = NameStr(*DatumGetName(datum));
  			}
! 			else
  			{
! 				snprintf(namebuf, sizeof(namebuf), "%u",
! 						 HeapTupleGetOid(oldtup));
! 				objname = namebuf;
  			}
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
+ 		}
+ 		/* Must be able to become new owner */
+ 		check_is_member_of_role(GetUserId(), new_ownerId);
+ 
+ 		/* New owner must have CREATE privilege on namespace */
+ 		if (OidIsValid(namespaceId))
+ 		{
+ 			AclResult	aclresult;
+ 
+ 			aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
+ 											  ACL_CREATE);
+ 			if (aclresult != ACLCHECK_OK)
+ 				aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 							   get_namespace_name(namespaceId));
  		}
  
  		/* Build a modified tuple */
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
new file mode 100644
index ab4ed6c..aad6ae4
*** a/src/backend/commands/foreigncmds.c
--- b/src/backend/commands/foreigncmds.c
*************** AlterForeignServerOwner_internal(Relatio
*** 332,361 ****
  
  	if (form->srvowner != newOwnerId)
  	{
! 		/* Superusers can always do it */
! 		if (!superuser())
! 		{
! 			Oid			srvId;
! 			AclResult	aclresult;
  
! 			srvId = HeapTupleGetOid(tup);
  
! 			/* Must be owner */
! 			if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
! 				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
! 							   NameStr(form->srvname));
  
! 			/* Must be able to become new owner */
! 			check_is_member_of_role(GetUserId(), newOwnerId);
  
! 			/* New owner must have USAGE privilege on foreign-data wrapper */
! 			aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
! 			if (aclresult != ACLCHECK_OK)
! 			{
! 				ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
  
! 				aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
! 			}
  		}
  
  		form->srvowner = newOwnerId;
--- 332,359 ----
  
  	if (form->srvowner != newOwnerId)
  	{
! 		Oid			srvId;
! 		AclResult	aclresult;
  
! 		srvId = HeapTupleGetOid(tup);
  
! 		/* Must be owner */
! 		if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
! 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
! 						   NameStr(form->srvname));
  
! 		/* Must be able to become new owner */
! 		check_is_member_of_role(GetUserId(), newOwnerId);
  
! 		/* New owner must have USAGE privilege on foreign-data wrapper */
! 		aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId,
! 													 ACL_USAGE);
  
! 		if (aclresult != ACLCHECK_OK)
! 		{
! 			ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
! 
! 			aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
  		}
  
  		form->srvowner = newOwnerId;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index ecdff1e..5fb470f
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecChangeOwner(Oid relationOid, Oid n
*** 8625,8651 ****
  		/* skip permission checks when recursing to index or toast table */
  		if (!recursing)
  		{
! 			/* Superusers can always do it */
! 			if (!superuser())
! 			{
! 				Oid			namespaceOid = tuple_class->relnamespace;
! 				AclResult	aclresult;
  
! 				/* Otherwise, must be owner of the existing object */
! 				if (!pg_class_ownercheck(relationOid, GetUserId()))
! 					aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
! 								   RelationGetRelationName(target_rel));
  
! 				/* Must be able to become new owner */
! 				check_is_member_of_role(GetUserId(), newOwnerId);
  
! 				/* New owner must have CREATE privilege on namespace */
! 				aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
! 												  ACL_CREATE);
! 				if (aclresult != ACLCHECK_OK)
! 					aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 								   get_namespace_name(namespaceOid));
! 			}
  		}
  
  		memset(repl_null, false, sizeof(repl_null));
--- 8625,8647 ----
  		/* skip permission checks when recursing to index or toast table */
  		if (!recursing)
  		{
! 			Oid			namespaceOid = tuple_class->relnamespace;
! 			AclResult	aclresult;
  
! 			/* Must be owner of the existing object */
! 			if (!pg_class_ownercheck(relationOid, GetUserId()))
! 				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
! 							   RelationGetRelationName(target_rel));
  
! 			/* Must be able to become new owner */
! 			check_is_member_of_role(GetUserId(), newOwnerId);
  
! 			/* New owner must have CREATE privilege on namespace */
! 			aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
! 											  ACL_CREATE);
! 			if (aclresult != ACLCHECK_OK)
! 				aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 							   get_namespace_name(namespaceOid));
  		}
  
  		memset(repl_null, false, sizeof(repl_null));
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
new file mode 100644
index 55a6881..c25e237
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
*************** AlterTypeOwner(List *names, Oid newOwner
*** 3302,3325 ****
  	 */
  	if (typTup->typowner != newOwnerId)
  	{
! 		/* Superusers can always do it */
! 		if (!superuser())
! 		{
! 			/* Otherwise, must be owner of the existing object */
! 			if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
! 				aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
  
! 			/* Must be able to become new owner */
! 			check_is_member_of_role(GetUserId(), newOwnerId);
  
! 			/* New owner must have CREATE privilege on namespace */
! 			aclresult = pg_namespace_aclcheck(typTup->typnamespace,
! 											  newOwnerId,
! 											  ACL_CREATE);
! 			if (aclresult != ACLCHECK_OK)
! 				aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 							   get_namespace_name(typTup->typnamespace));
! 		}
  
  		/*
  		 * If it's a composite type, invoke ATExecChangeOwner so that we fix
--- 3302,3321 ----
  	 */
  	if (typTup->typowner != newOwnerId)
  	{
! 		/* Must be owner of the existing object */
! 		if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
! 			aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
  
! 		/* Must be able to become new owner */
! 		check_is_member_of_role(GetUserId(), newOwnerId);
  
! 		/* New owner must have CREATE privilege on namespace */
! 		aclresult = pg_namespace_aclcheck(typTup->typnamespace,
! 										  newOwnerId,
! 										  ACL_CREATE);
! 		if (aclresult != ACLCHECK_OK)
! 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 						   get_namespace_name(typTup->typnamespace));
  
  		/*
  		 * If it's a composite type, invoke ATExecChangeOwner so that we fix
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
new file mode 100644
index 1a73fd8..6e4cd8b
*** a/src/backend/commands/user.c
--- b/src/backend/commands/user.c
*************** static void DelRoleMems(const char *role
*** 55,69 ****
  			List *memberNames, List *memberIds,
  			bool admin_opt);
  
- 
- /* Check if current user has createrole privileges */
- static bool
- have_createrole_privilege(void)
- {
- 	return has_createrole_privilege(GetUserId());
- }
- 
- 
  /*
   * CREATE ROLE
   */
--- 55,60 ----
*************** CreateRole(CreateRoleStmt *stmt)
*** 88,93 ****
--- 79,88 ----
  	bool		canlogin = false;		/* Can this user login? */
  	bool		isreplication = false;	/* Is this a replication role? */
  	bool		bypassrls = false;		/* Is this a row security enabled role? */
+ 	bool		backup = false;
+ 	bool		logrotate = false;
+ 	bool		monitor = false;
+ 	bool		procsignal = false;
  	int			connlimit = -1; /* maximum connections allowed */
  	List	   *addroleto = NIL;	/* roles to make this a member of */
  	List	   *rolemembers = NIL;		/* roles to be members of this role */
*************** CreateRole(CreateRoleStmt *stmt)
*** 108,113 ****
--- 103,112 ----
  	DefElem    *dadminmembers = NULL;
  	DefElem    *dvalidUntil = NULL;
  	DefElem    *dbypassRLS = NULL;
+ 	DefElem    *dbackup = NULL;
+ 	DefElem    *dlogrotate = NULL;
+ 	DefElem    *dmonitor = NULL;
+ 	DefElem    *dprocsignal = NULL;
  
  	/* The defaults can vary depending on the original statement type */
  	switch (stmt->stmt_type)
*************** CreateRole(CreateRoleStmt *stmt)
*** 242,247 ****
--- 241,278 ----
  						 errmsg("conflicting or redundant options")));
  			dbypassRLS = defel;
  		}
+ 		else if (strcmp(defel->defname, "backup") == 0)
+ 		{
+ 			if (dbackup)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dbackup = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "logrotate") == 0)
+ 		{
+ 			if (dlogrotate)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dlogrotate = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "monitor") == 0)
+ 		{
+ 			if (dmonitor)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dmonitor = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "procsignal") == 0)
+ 		{
+ 			if (dprocsignal)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dprocsignal = defel;
+ 		}
  		else
  			elog(ERROR, "option \"%s\" not recognized",
  				 defel->defname);
*************** CreateRole(CreateRoleStmt *stmt)
*** 279,284 ****
--- 310,323 ----
  		validUntil = strVal(dvalidUntil->arg);
  	if (dbypassRLS)
  		bypassrls = intVal(dbypassRLS->arg) != 0;
+ 	if (dbackup)
+ 		backup = intVal(dbackup->arg) != 0;
+ 	if (dlogrotate)
+ 		logrotate = intVal(dlogrotate->arg) != 0;
+ 	if (dmonitor)
+ 		monitor = intVal(dmonitor->arg) != 0;
+ 	if (dprocsignal)
+ 		procsignal = intVal(dprocsignal->arg) != 0;
  
  	/* Check some permissions first */
  	if (issuper)
*************** CreateRole(CreateRoleStmt *stmt)
*** 304,310 ****
  	}
  	else
  	{
! 		if (!have_createrole_privilege())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("permission denied to create role")));
--- 343,349 ----
  	}
  	else
  	{
! 		if (!has_createrole_privilege(GetUserId()))
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("permission denied to create role")));
*************** CreateRole(CreateRoleStmt *stmt)
*** 395,400 ****
--- 434,443 ----
  	new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
  
  	new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
+ 	new_record[Anum_pg_authid_rolbackup - 1] = BoolGetDatum(backup);
+ 	new_record[Anum_pg_authid_rollogrotate - 1] = BoolGetDatum(logrotate);
+ 	new_record[Anum_pg_authid_rolmonitor - 1] = BoolGetDatum(monitor);
+ 	new_record[Anum_pg_authid_rolprocsignal - 1] = BoolGetDatum(procsignal);
  
  	tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
  
*************** AlterRole(AlterRoleStmt *stmt)
*** 496,501 ****
--- 539,548 ----
  	Datum		validUntil_datum;		/* same, as timestamptz Datum */
  	bool		validUntil_null;
  	bool		bypassrls = -1;
+ 	bool		backup = -1;
+ 	bool		logrotate = -1;
+ 	bool		monitor = -1;
+ 	bool		procsignal = -1;
  	DefElem    *dpassword = NULL;
  	DefElem    *dissuper = NULL;
  	DefElem    *dinherit = NULL;
*************** AlterRole(AlterRoleStmt *stmt)
*** 507,512 ****
--- 554,563 ----
  	DefElem    *drolemembers = NULL;
  	DefElem    *dvalidUntil = NULL;
  	DefElem    *dbypassRLS = NULL;
+ 	DefElem    *dbackup = NULL;
+ 	DefElem    *dlogrotate = NULL;
+ 	DefElem    *dmonitor = NULL;
+ 	DefElem    *dprocsignal = NULL;
  	Oid			roleid;
  
  	/* Extract options from the statement node tree */
*************** AlterRole(AlterRoleStmt *stmt)
*** 609,614 ****
--- 660,697 ----
  						 errmsg("conflicting or redundant options")));
  			dbypassRLS = defel;
  		}
+ 		else if (strcmp(defel->defname, "backup") == 0)
+ 		{
+ 			if (dbackup)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dbackup = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "logrotate") == 0)
+ 		{
+ 			if (dlogrotate)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dlogrotate = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "monitor") == 0)
+ 		{
+ 			if (dmonitor)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dmonitor = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "procsignal") == 0)
+ 		{
+ 			if (dprocsignal)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options")));
+ 			dprocsignal = defel;
+ 		}
  		else
  			elog(ERROR, "option \"%s\" not recognized",
  				 defel->defname);
*************** AlterRole(AlterRoleStmt *stmt)
*** 642,647 ****
--- 725,738 ----
  		validUntil = strVal(dvalidUntil->arg);
  	if (dbypassRLS)
  		bypassrls = intVal(dbypassRLS->arg);
+ 	if (dbackup)
+ 		backup = intVal(dbackup->arg);
+ 	if (dlogrotate)
+ 		logrotate = intVal(dlogrotate->arg);
+ 	if (dmonitor)
+ 		monitor = intVal(dmonitor->arg);
+ 	if (dprocsignal)
+ 		procsignal = intVal(dprocsignal->arg);
  
  	/*
  	 * Scan the pg_authid relation to be certain the user exists.
*************** AlterRole(AlterRoleStmt *stmt)
*** 682,694 ****
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to change bypassrls attribute")));
  	}
! 	else if (!have_createrole_privilege())
  	{
  		if (!(inherit < 0 &&
  			  createrole < 0 &&
  			  createdb < 0 &&
  			  canlogin < 0 &&
  			  isreplication < 0 &&
  			  !dconnlimit &&
  			  !rolemembers &&
  			  !validUntil &&
--- 773,789 ----
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to change bypassrls attribute")));
  	}
! 	else if (!has_createrole_privilege(GetUserId()))
  	{
  		if (!(inherit < 0 &&
  			  createrole < 0 &&
  			  createdb < 0 &&
  			  canlogin < 0 &&
  			  isreplication < 0 &&
+ 			  backup < 0 &&
+ 			  logrotate < 0 &&
+ 			  monitor < 0 &&
+ 			  procsignal < 0 &&
  			  !dconnlimit &&
  			  !rolemembers &&
  			  !validUntil &&
*************** AlterRole(AlterRoleStmt *stmt)
*** 821,826 ****
--- 916,945 ----
  		new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
  	}
  
+ 	if (backup >= 0)
+ 	{
+ 		new_record[Anum_pg_authid_rolbackup - 1] = BoolGetDatum(backup > 0);
+ 		new_record_repl[Anum_pg_authid_rolbackup - 1] = true;
+ 	}
+ 
+ 	if (logrotate >= 0)
+ 	{
+ 		new_record[Anum_pg_authid_rollogrotate - 1] = BoolGetDatum(logrotate > 0);
+ 		new_record_repl[Anum_pg_authid_rollogrotate - 1] = true;
+ 	}
+ 
+ 	if (monitor >= 0)
+ 	{
+ 		new_record[Anum_pg_authid_rolmonitor - 1] = BoolGetDatum(monitor > 0);
+ 		new_record_repl[Anum_pg_authid_rolmonitor - 1] = true;
+ 	}
+ 
+ 	if (procsignal >= 0)
+ 	{
+ 		new_record[Anum_pg_authid_rolprocsignal - 1] = BoolGetDatum(procsignal > 0);
+ 		new_record_repl[Anum_pg_authid_rolprocsignal - 1] = true;
+ 	}
+ 
  	new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
  								  new_record_nulls, new_record_repl);
  	simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);
*************** AlterRoleSet(AlterRoleSetStmt *stmt)
*** 898,904 ****
  		}
  		else
  		{
! 			if (!have_createrole_privilege() &&
  				HeapTupleGetOid(roletuple) != GetUserId())
  				ereport(ERROR,
  						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1017,1023 ----
  		}
  		else
  		{
! 			if (!has_createrole_privilege(GetUserId()) &&
  				HeapTupleGetOid(roletuple) != GetUserId())
  				ereport(ERROR,
  						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DropRole(DropRoleStmt *stmt)
*** 951,957 ****
  				pg_auth_members_rel;
  	ListCell   *item;
  
! 	if (!have_createrole_privilege())
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("permission denied to drop role")));
--- 1070,1076 ----
  				pg_auth_members_rel;
  	ListCell   *item;
  
! 	if (!has_createrole_privilege(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("permission denied to drop role")));
*************** RenameRole(const char *oldname, const ch
*** 1182,1188 ****
  	}
  	else
  	{
! 		if (!have_createrole_privilege())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("permission denied to rename role")));
--- 1301,1307 ----
  	}
  	else
  	{
! 		if (!has_createrole_privilege(GetUserId()))
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("permission denied to rename role")));
*************** AddRoleMems(const char *rolename, Oid ro
*** 1409,1415 ****
  	}
  	else
  	{
! 		if (!have_createrole_privilege() &&
  			!is_admin_of_role(grantorId, roleid))
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1528,1534 ----
  	}
  	else
  	{
! 		if (!has_createrole_privilege(GetUserId()) &&
  			!is_admin_of_role(grantorId, roleid))
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DelRoleMems(const char *rolename, Oid ro
*** 1555,1561 ****
  	}
  	else
  	{
! 		if (!have_createrole_privilege() &&
  			!is_admin_of_role(GetUserId(), roleid))
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1674,1680 ----
  	}
  	else
  	{
! 		if (!has_createrole_privilege(GetUserId()) &&
  			!is_admin_of_role(GetUserId(), roleid))
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index c98c27a..f23a5f3
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** AlterOptRoleElem:
*** 977,982 ****
--- 977,998 ----
  						 */
  						$$ = makeDefElem("inherit", (Node *)makeInteger(FALSE));
  					}
+ 					else if (strcmp($1, "backup") == 0)
+ 						$$ = makeDefElem("backup", (Node *)makeInteger(TRUE));
+ 					else if (strcmp($1, "nobackup") == 0)
+ 						$$ = makeDefElem("backup", (Node *)makeInteger(FALSE));
+ 					else if (strcmp($1, "logrotate") == 0)
+ 						$$ = makeDefElem("logrotate", (Node *)makeInteger(TRUE));
+ 					else if (strcmp($1, "nologrotate") == 0)
+ 						$$ = makeDefElem("logrotate", (Node *)makeInteger(FALSE));
+ 					else if (strcmp($1, "monitor") == 0)
+ 						$$ = makeDefElem("monitor", (Node *)makeInteger(TRUE));
+ 					else if (strcmp($1, "nomonitor") == 0)
+ 						$$ = makeDefElem("monitor", (Node *)makeInteger(FALSE));
+ 					else if (strcmp($1, "procsignal") == 0)
+ 						$$ = makeDefElem("procsignal", (Node *)makeInteger(TRUE));
+ 					else if (strcmp($1, "noprocsignal") == 0)
+ 						$$ = makeDefElem("procsignal", (Node *)makeInteger(FALSE));
  					else
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
new file mode 100644
index 3a5ec2f..a7417c9
*** a/src/backend/replication/logical/logicalfuncs.c
--- b/src/backend/replication/logical/logicalfuncs.c
***************
*** 27,32 ****
--- 27,33 ----
  
  #include "mb/pg_wchar.h"
  
+ #include "utils/acl.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
  #include "utils/inval.h"
*************** XLogRead(char *buf, TimeLineID tli, XLog
*** 200,214 ****
  	}
  }
  
- static void
- check_permissions(void)
- {
- 	if (!superuser() && !has_rolreplication(GetUserId()))
- 		ereport(ERROR,
- 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- 				 (errmsg("must be superuser or replication role to use replication slots"))));
- }
- 
  /*
   * read_page callback for logical decoding contexts.
   *
--- 201,206 ----
*************** pg_logical_slot_get_changes_guts(Functio
*** 322,328 ****
  	if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  
! 	check_permissions();
  
  	CheckLogicalDecodingRequirements();
  
--- 314,323 ----
  	if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  
! 	if (!has_replication_privilege(GetUserId()))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser or replication role to use replication slots")));
  
  	CheckLogicalDecodingRequirements();
  
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
new file mode 100644
index bd4701f..ebae1a2
*** a/src/backend/replication/slotfuncs.c
--- b/src/backend/replication/slotfuncs.c
***************
*** 20,37 ****
  #include "replication/slot.h"
  #include "replication/logical.h"
  #include "replication/logicalfuncs.h"
  #include "utils/builtins.h"
  #include "utils/pg_lsn.h"
  
- static void
- check_permissions(void)
- {
- 	if (!superuser() && !has_rolreplication(GetUserId()))
- 		ereport(ERROR,
- 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- 				 (errmsg("must be superuser or replication role to use replication slots"))));
- }
- 
  /*
   * SQL function for creating a new physical (streaming replication)
   * replication slot.
--- 20,29 ----
  #include "replication/slot.h"
  #include "replication/logical.h"
  #include "replication/logicalfuncs.h"
+ #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/pg_lsn.h"
  
  /*
   * SQL function for creating a new physical (streaming replication)
   * replication slot.
*************** pg_create_physical_replication_slot(PG_F
*** 51,57 ****
  	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  
! 	check_permissions();
  
  	CheckSlotRequirements();
  
--- 43,52 ----
  	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  
! 	if (!has_replication_privilege(GetUserId()))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser or replication role to use replication slots")));
  
  	CheckSlotRequirements();
  
*************** pg_create_logical_replication_slot(PG_FU
*** 94,100 ****
  	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  
! 	check_permissions();
  
  	CheckLogicalDecodingRequirements();
  
--- 89,98 ----
  	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  
! 	if (!has_replication_privilege(GetUserId()))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser or replication role to use replication slots")));
  
  	CheckLogicalDecodingRequirements();
  
*************** pg_drop_replication_slot(PG_FUNCTION_ARG
*** 143,149 ****
  {
  	Name		name = PG_GETARG_NAME(0);
  
! 	check_permissions();
  
  	CheckSlotRequirements();
  
--- 141,150 ----
  {
  	Name		name = PG_GETARG_NAME(0);
  
! 	if (!has_replication_privilege(GetUserId()))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser or replication role to use replication slots")));
  
  	CheckSlotRequirements();
  
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
new file mode 100644
index 384c9b6..456bf46
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
***************
*** 72,77 ****
--- 72,78 ----
  #include "storage/proc.h"
  #include "storage/procarray.h"
  #include "tcop/tcopprot.h"
+ #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
  #include "utils/memutils.h"
*************** pg_stat_get_wal_senders(PG_FUNCTION_ARGS
*** 2832,2842 ****
  		memset(nulls, 0, sizeof(nulls));
  		values[0] = Int32GetDatum(walsnd->pid);
  
! 		if (!superuser())
  		{
  			/*
! 			 * Only superusers can see details. Other users only get the pid
! 			 * value to know it's a walsender, but no details.
  			 */
  			MemSet(&nulls[1], true, PG_STAT_GET_WAL_SENDERS_COLS - 1);
  		}
--- 2833,2844 ----
  		memset(nulls, 0, sizeof(nulls));
  		values[0] = Int32GetDatum(walsnd->pid);
  
! 		if (!has_monitor_privilege(GetUserId()))
  		{
  			/*
! 			 * Only users with the MONITOR attribute or superuser privileges can
! 			 * see details. Other users only get the pid value to know it's a
! 			 * walsender, but no details.
  			 */
  			MemSet(&nulls[1], true, PG_STAT_GET_WAL_SENDERS_COLS - 1);
  		}
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
new file mode 100644
index dc6eb2c..4f9ffe5
*** a/src/backend/utils/adt/acl.c
--- b/src/backend/utils/adt/acl.c
*************** static AclMode convert_role_priv_string(
*** 117,122 ****
--- 117,123 ----
  static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
  
  static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
+ static bool has_inherit_privilege(Oid roleid);
  
  
  /*
*************** RoleMembershipCacheCallback(Datum arg, i
*** 4636,4642 ****
  
  /* Check if specified role has rolinherit set */
  static bool
! has_rolinherit(Oid roleid)
  {
  	bool		result = false;
  	HeapTuple	utup;
--- 4637,4643 ----
  
  /* Check if specified role has rolinherit set */
  static bool
! has_inherit_privilege(Oid roleid)
  {
  	bool		result = false;
  	HeapTuple	utup;
*************** roles_has_privs_of(Oid roleid)
*** 4697,4703 ****
  		int			i;
  
  		/* Ignore non-inheriting roles */
! 		if (!has_rolinherit(memberid))
  			continue;
  
  		/* Find roles that memberid is directly a member of */
--- 4698,4704 ----
  		int			i;
  
  		/* Ignore non-inheriting roles */
! 		if (!has_inherit_privilege(memberid))
  			continue;
  
  		/* Find roles that memberid is directly a member of */
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
new file mode 100644
index 67539ec..0515b8f
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 37,42 ****
--- 37,43 ----
  #include "utils/lsyscache.h"
  #include "utils/ruleutils.h"
  #include "tcop/tcopprot.h"
+ #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/timestamp.h"
  
*************** pg_signal_backend(int pid, int sig)
*** 113,119 ****
  		return SIGNAL_BACKEND_ERROR;
  	}
  
! 	if (!(superuser() || proc->roleId == GetUserId()))
  		return SIGNAL_BACKEND_NOPERMISSION;
  
  	/*
--- 114,132 ----
  		return SIGNAL_BACKEND_ERROR;
  	}
  
! 	/*
! 	 * If the current user is not a superuser, then they aren't allowed to
! 	 * signal backends which are owned by a superuser.
! 	 */
! 	if (!superuser() && superuser_arg(proc->roleId))
! 		return SIGNAL_BACKEND_NOPERMISSION;
! 
! 	/*
! 	 * If the current user is not a member of the role owning the process and
! 	 * does not have the PROCSIGNAL permission, then permission is denied.
! 	 */
! 	if (!has_privs_of_role(GetUserId(), proc->roleId)
! 		&& !has_procsignal_privilege(GetUserId()))
  		return SIGNAL_BACKEND_NOPERMISSION;
  
  	/*
*************** pg_reload_conf(PG_FUNCTION_ARGS)
*** 202,211 ****
  Datum
  pg_rotate_logfile(PG_FUNCTION_ARGS)
  {
! 	if (!superuser())
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 (errmsg("must be superuser to rotate log files"))));
  
  	if (!Logging_collector)
  	{
--- 215,224 ----
  Datum
  pg_rotate_logfile(PG_FUNCTION_ARGS)
  {
! 	if (!has_logrotate_privilege(GetUserId()))
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 errmsg("must be superuser or have logrotate permission to rotate log files")));
  
  	if (!Logging_collector)
  	{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
new file mode 100644
index 44ccd37..c960ebb
*** a/src/backend/utils/adt/pgstatfuncs.c
--- b/src/backend/utils/adt/pgstatfuncs.c
***************
*** 20,25 ****
--- 20,26 ----
  #include "libpq/ip.h"
  #include "miscadmin.h"
  #include "pgstat.h"
+ #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/inet.h"
  #include "utils/timestamp.h"
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 625,630 ****
--- 626,632 ----
  		HeapTuple	tuple;
  		LocalPgBackendStatus *local_beentry;
  		PgBackendStatus *beentry;
+ 		Oid			current_user_id;
  
  		MemSet(values, 0, sizeof(values));
  		MemSet(nulls, 0, sizeof(nulls));
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 674,681 ****
  		else
  			nulls[15] = true;
  
! 		/* Values only available to same user or superuser */
! 		if (superuser() || beentry->st_userid == GetUserId())
  		{
  			SockAddr	zero_clientaddr;
  
--- 676,689 ----
  		else
  			nulls[15] = true;
  
! 		/*
! 		 * Values only available to roles which are members of this role,
! 		 * or which have the MONITOR privilege.
! 		 */
! 		current_user_id = GetUserId();
! 
! 		if (has_monitor_privilege(current_user_id)
! 			|| has_privs_of_role(current_user_id, beentry->st_userid))
  		{
  			SockAddr	zero_clientaddr;
  
*************** pg_stat_get_backend_activity(PG_FUNCTION
*** 874,883 ****
  	int32		beid = PG_GETARG_INT32(0);
  	PgBackendStatus *beentry;
  	const char *activity;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		activity = "<backend information not available>";
! 	else if (!superuser() && beentry->st_userid != GetUserId())
  		activity = "<insufficient privilege>";
  	else if (*(beentry->st_activity) == '\0')
  		activity = "<command string not enabled>";
--- 882,895 ----
  	int32		beid = PG_GETARG_INT32(0);
  	PgBackendStatus *beentry;
  	const char *activity;
+ 	Oid			current_user_id;
+ 
+ 	current_user_id = GetUserId();
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		activity = "<backend information not available>";
! 	else if (!has_monitor_privilege(current_user_id)
! 			 && !has_privs_of_role(current_user_id, beentry->st_userid))
  		activity = "<insufficient privilege>";
  	else if (*(beentry->st_activity) == '\0')
  		activity = "<command string not enabled>";
*************** pg_stat_get_backend_waiting(PG_FUNCTION_
*** 894,904 ****
  	int32		beid = PG_GETARG_INT32(0);
  	bool		result;
  	PgBackendStatus *beentry;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	if (!superuser() && beentry->st_userid != GetUserId())
  		PG_RETURN_NULL();
  
  	result = beentry->st_waiting;
--- 906,920 ----
  	int32		beid = PG_GETARG_INT32(0);
  	bool		result;
  	PgBackendStatus *beentry;
+ 	Oid			current_user_id;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	current_user_id = GetUserId();
! 
! 	if (!has_monitor_privilege(current_user_id)
! 		&& !has_privs_of_role(current_user_id, beentry->st_userid))
  		PG_RETURN_NULL();
  
  	result = beentry->st_waiting;
*************** pg_stat_get_backend_activity_start(PG_FU
*** 913,923 ****
  	int32		beid = PG_GETARG_INT32(0);
  	TimestampTz result;
  	PgBackendStatus *beentry;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	if (!superuser() && beentry->st_userid != GetUserId())
  		PG_RETURN_NULL();
  
  	result = beentry->st_activity_start_timestamp;
--- 929,943 ----
  	int32		beid = PG_GETARG_INT32(0);
  	TimestampTz result;
  	PgBackendStatus *beentry;
+ 	Oid			current_user_id;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	current_user_id = GetUserId();
! 
! 	if (!has_monitor_privilege(current_user_id)
! 		&& !has_privs_of_role(current_user_id, beentry->st_userid))
  		PG_RETURN_NULL();
  
  	result = beentry->st_activity_start_timestamp;
*************** pg_stat_get_backend_xact_start(PG_FUNCTI
*** 939,949 ****
  	int32		beid = PG_GETARG_INT32(0);
  	TimestampTz result;
  	PgBackendStatus *beentry;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	if (!superuser() && beentry->st_userid != GetUserId())
  		PG_RETURN_NULL();
  
  	result = beentry->st_xact_start_timestamp;
--- 959,973 ----
  	int32		beid = PG_GETARG_INT32(0);
  	TimestampTz result;
  	PgBackendStatus *beentry;
+ 	Oid			current_user_id;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	current_user_id = GetUserId();
! 
! 	if (!has_monitor_privilege(current_user_id)
! 		&& !has_privs_of_role(current_user_id, beentry->st_userid))
  		PG_RETURN_NULL();
  
  	result = beentry->st_xact_start_timestamp;
*************** pg_stat_get_backend_start(PG_FUNCTION_AR
*** 961,971 ****
  	int32		beid = PG_GETARG_INT32(0);
  	TimestampTz result;
  	PgBackendStatus *beentry;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	if (!superuser() && beentry->st_userid != GetUserId())
  		PG_RETURN_NULL();
  
  	result = beentry->st_proc_start_timestamp;
--- 985,999 ----
  	int32		beid = PG_GETARG_INT32(0);
  	TimestampTz result;
  	PgBackendStatus *beentry;
+ 	Oid			current_user_id;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	current_user_id = GetUserId();
! 
! 	if (!has_monitor_privilege(current_user_id)
! 		&& !has_privs_of_role(current_user_id, beentry->st_userid))
  		PG_RETURN_NULL();
  
  	result = beentry->st_proc_start_timestamp;
*************** pg_stat_get_backend_client_addr(PG_FUNCT
*** 985,995 ****
  	SockAddr	zero_clientaddr;
  	char		remote_host[NI_MAXHOST];
  	int			ret;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	if (!superuser() && beentry->st_userid != GetUserId())
  		PG_RETURN_NULL();
  
  	/* A zeroed client addr means we don't know */
--- 1013,1027 ----
  	SockAddr	zero_clientaddr;
  	char		remote_host[NI_MAXHOST];
  	int			ret;
+ 	Oid			current_user_id;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	current_user_id = GetUserId();
! 
! 	if (!has_monitor_privilege(current_user_id)
! 		&& !has_privs_of_role(current_user_id, beentry->st_userid))
  		PG_RETURN_NULL();
  
  	/* A zeroed client addr means we don't know */
*************** pg_stat_get_backend_client_port(PG_FUNCT
*** 1032,1042 ****
  	SockAddr	zero_clientaddr;
  	char		remote_port[NI_MAXSERV];
  	int			ret;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	if (!superuser() && beentry->st_userid != GetUserId())
  		PG_RETURN_NULL();
  
  	/* A zeroed client addr means we don't know */
--- 1064,1082 ----
  	SockAddr	zero_clientaddr;
  	char		remote_port[NI_MAXSERV];
  	int			ret;
+ 	Oid			current_user_id;
  
  	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
  		PG_RETURN_NULL();
  
! 	/*
! 	 * User must have MONITOR attribute, be superuser or be the same
! 	 * backend user.
! 	 */
! 	current_user_id = GetUserId();
! 
! 	if (!has_monitor_privilege(current_user_id)
! 		&& !has_privs_of_role(current_user_id, beentry->st_userid))
  		PG_RETURN_NULL();
  
  	/* A zeroed client addr means we don't know */
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
new file mode 100644
index a703c67..2e41dc5
*** a/src/backend/utils/init/miscinit.c
--- b/src/backend/utils/init/miscinit.c
*************** SetUserIdAndContext(Oid userid, bool sec
*** 317,341 ****
  		SecurityRestrictionContext &= ~SECURITY_LOCAL_USERID_CHANGE;
  }
  
- 
- /*
-  * Check whether specified role has explicit REPLICATION privilege
-  */
- bool
- has_rolreplication(Oid roleid)
- {
- 	bool		result = false;
- 	HeapTuple	utup;
- 
- 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
- 	if (HeapTupleIsValid(utup))
- 	{
- 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
- 		ReleaseSysCache(utup);
- 	}
- 	return result;
- }
- 
  /*
   * Initialize user identity during normal backend startup
   */
--- 317,322 ----
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
new file mode 100644
index 6a6a445..28c25f4
*** a/src/backend/utils/init/postinit.c
--- b/src/backend/utils/init/postinit.c
*************** InitPostgres(const char *in_dbname, Oid
*** 761,767 ****
  	{
  		Assert(!bootstrap);
  
! 		if (!superuser() && !has_rolreplication(GetUserId()))
  			ereport(FATAL,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser or replication role to start walsender")));
--- 761,767 ----
  	{
  		Assert(!bootstrap);
  
! 		if (!has_replication_privilege(GetUserId()))
  			ereport(FATAL,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser or replication role to start walsender")));
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
new file mode 100644
index 3b63d2b..b636925
*** a/src/include/catalog/pg_authid.h
--- b/src/include/catalog/pg_authid.h
*************** CATALOG(pg_authid,1260) BKI_SHARED_RELAT
*** 53,58 ****
--- 53,62 ----
  	bool		rolcanlogin;	/* allowed to log in as session user? */
  	bool		rolreplication; /* role used for streaming replication */
  	bool		rolbypassrls;	/* allowed to bypass row level security? */
+ 	bool		rolbackup;		/* allowed to peform backup operations? */
+ 	bool		rollogrotate;	/* allowed to rotate log files? */
+ 	bool		rolmonitor;		/* allowed to view pg_stat_* details? */
+ 	bool		rolprocsignal;	/* allowed to signal backed processes? */
  	int32		rolconnlimit;	/* max connections allowed (-1=no limit) */
  
  	/* remaining fields may be null; use heap_getattr to read them! */
*************** typedef FormData_pg_authid *Form_pg_auth
*** 74,80 ****
   *		compiler constants for pg_authid
   * ----------------
   */
! #define Natts_pg_authid					12
  #define Anum_pg_authid_rolname			1
  #define Anum_pg_authid_rolsuper			2
  #define Anum_pg_authid_rolinherit		3
--- 78,84 ----
   *		compiler constants for pg_authid
   * ----------------
   */
! #define Natts_pg_authid					16
  #define Anum_pg_authid_rolname			1
  #define Anum_pg_authid_rolsuper			2
  #define Anum_pg_authid_rolinherit		3
*************** typedef FormData_pg_authid *Form_pg_auth
*** 84,92 ****
  #define Anum_pg_authid_rolcanlogin		7
  #define Anum_pg_authid_rolreplication	8
  #define Anum_pg_authid_rolbypassrls		9
! #define Anum_pg_authid_rolconnlimit		10
! #define Anum_pg_authid_rolpassword		11
! #define Anum_pg_authid_rolvaliduntil	12
  
  /* ----------------
   *		initial contents of pg_authid
--- 88,100 ----
  #define Anum_pg_authid_rolcanlogin		7
  #define Anum_pg_authid_rolreplication	8
  #define Anum_pg_authid_rolbypassrls		9
! #define Anum_pg_authid_rolbackup		10
! #define Anum_pg_authid_rollogrotate		11
! #define Anum_pg_authid_rolmonitor		12
! #define Anum_pg_authid_rolprocsignal	13
! #define Anum_pg_authid_rolconnlimit		14
! #define Anum_pg_authid_rolpassword		15
! #define Anum_pg_authid_rolvaliduntil	16
  
  /* ----------------
   *		initial contents of pg_authid
*************** typedef FormData_pg_authid *Form_pg_auth
*** 95,101 ****
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t -1 _null_ _null_));
  
  #define BOOTSTRAP_SUPERUSERID 10
  
--- 103,109 ----
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t t t t t -1 _null_ _null_));
  
  #define BOOTSTRAP_SUPERUSERID 10
  
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
new file mode 100644
index 2ba9885..011bd62
*** a/src/include/miscadmin.h
--- b/src/include/miscadmin.h
*************** extern void ValidatePgVersion(const char
*** 434,440 ****
  extern void process_shared_preload_libraries(void);
  extern void process_session_preload_libraries(void);
  extern void pg_bindtextdomain(const char *domain);
- extern bool has_rolreplication(Oid roleid);
  
  /* in access/transam/xlog.c */
  extern bool BackupInProgress(void);
--- 434,439 ----
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
new file mode 100644
index a8e3164..ac242b2
*** a/src/include/utils/acl.h
--- b/src/include/utils/acl.h
*************** extern bool pg_event_trigger_ownercheck(
*** 328,332 ****
--- 328,337 ----
  extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
  extern bool has_createrole_privilege(Oid roleid);
  extern bool has_bypassrls_privilege(Oid roleid);
+ extern bool has_replication_privilege(Oid roleid);
+ extern bool has_backup_privilege(Oid roleid);
+ extern bool has_logrotate_privilege(Oid roleid);
+ extern bool has_monitor_privilege(Oid roleid);
+ extern bool has_procsignal_privilege(Oid roleid);
  
  #endif   /* ACL_H */
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
new file mode 100644
index e4dedb0..b3b5cd0
*** a/src/test/regress/expected/foreign_data.out
--- b/src/test/regress/expected/foreign_data.out
*************** ERROR:  must be owner of foreign server
*** 394,399 ****
--- 394,400 ----
  ALTER SERVER s1 OWNER TO regress_test_role;                 -- ERROR
  ERROR:  must be owner of foreign server s1
  RESET ROLE;
+ GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
  ALTER SERVER s1 OWNER TO regress_test_role;
  GRANT regress_test_role2 TO regress_test_role;
  SET ROLE regress_test_role;
*************** GRANT USAGE ON FOREIGN DATA WRAPPER foo
*** 417,422 ****
--- 418,424 ----
  SET ROLE regress_test_role;
  ALTER SERVER s1 OWNER TO regress_test_indirect;
  RESET ROLE;
+ REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role;
  DROP ROLE regress_test_indirect;                            -- ERROR
  ERROR:  role "regress_test_indirect" cannot be dropped because some objects depend on it
  DETAIL:  owner of server s1
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
new file mode 100644
index de9dbc8..91d51c9
*** a/src/test/regress/sql/foreign_data.sql
--- b/src/test/regress/sql/foreign_data.sql
*************** SET ROLE regress_test_role;
*** 164,169 ****
--- 164,170 ----
  ALTER SERVER s1 VERSION '1.1';                              -- ERROR
  ALTER SERVER s1 OWNER TO regress_test_role;                 -- ERROR
  RESET ROLE;
+ GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
  ALTER SERVER s1 OWNER TO regress_test_role;
  GRANT regress_test_role2 TO regress_test_role;
  SET ROLE regress_test_role;
*************** GRANT USAGE ON FOREIGN DATA WRAPPER foo
*** 183,188 ****
--- 184,190 ----
  SET ROLE regress_test_role;
  ALTER SERVER s1 OWNER TO regress_test_indirect;
  RESET ROLE;
+ REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role;
  DROP ROLE regress_test_indirect;                            -- ERROR
  \des+
  
