diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
new file mode 100644
index c9a9baf..73bdd0f
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
*************** AlterObjectOwner_internal(Relation rel,
*** 806,852 ****
  		Datum	   *values;
  		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 */
--- 806,849 ----
  		Datum	   *values;
  		bool	   *nulls;
  		bool	   *replaces;
+ 		AclObjectKind aclkind;
  
! 		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/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+
  
