# What is pg_database_owner in Postgres

> What pg_database_owner does in Postgres, why it was added, and how to use it without hitting the "cannot have explicit members" error.

Adela | 2025-09-18 | Source: https://www.bytebase.com/blog/what-is-pg-database-owner/

---

PostgreSQL 14 (released September 30, 2021) added a predefined role called **`pg_database_owner`**. It's a small addition, but it changes how you hand out privileges to whoever owns a database, and it removes some of the manual grant work that used to come with creating new databases from a template.

## What is `pg_database_owner`?

`pg_database_owner` is a **built-in role** that always maps to the **owner of the current database**. You never assign it. Whoever owns the database is the member, and that's decided for you.

* You don't grant it to users.
* Membership is **implicit and context-dependent**: whoever owns the database is the member.

The useful consequence is that privileges granted to `pg_database_owner` in a template database carry over automatically to any new database created from that template.

## Why it Exists

It solves two problems.

1. **Template Database Privileges**
   Before, keeping privileges consistent across databases meant granting them by hand every time. Now you grant once to `pg_database_owner` in a template, and every database created from it applies the same privileges.

2. **Safer Defaults**
   Starting in PostgreSQL 15, the `public` schema is owned by `pg_database_owner`. That gives each database owner direct control over schema access and closes the long-standing problem of a `public` schema that was open to everyone by default.

## Key Characteristics

| Property                           | Description                                    |
| ---------------------------------- | ---------------------------------------------- |
| **Implicit membership**            | Always maps to the database owner              |
| **Database scope**                 | Valid only in the current database             |
| **No login**                       | Cannot log in directly                         |
| **No explicit members**            | You cannot `GRANT ... TO pg_database_owner`    |
| **Template inheritance**           | Privileges granted in a template DB carry over |
| **Isolation**                      | Cannot be part of role hierarchies             |
| **Public schema ownership (v15+)** | Owns the `public` schema                       |

## Common Error

If you try to add a member to it explicitly, Postgres stops you:

```sql
GRANT pg_database_owner TO my_user;
ERROR: role "pg_database_owner" cannot have explicit members
```

That's expected. Membership is derived from ownership, not granted. So instead:

* Grant privileges *to* `pg_database_owner`
* Or transfer database ownership if you want a different effective owner

```sql
ALTER DATABASE mydb OWNER TO new_owner;
```

## Practical Examples

**Schema Privileges**

```sql
GRANT USAGE, CREATE ON SCHEMA app TO pg_database_owner;
ALTER DEFAULT PRIVILEGES IN SCHEMA app
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO pg_database_owner;
```

**Template Setup**
Grant monitoring or utility functions to `pg_database_owner` in a template database, and every new database owner inherits that access without you doing anything extra.

## Best Practices

**Do:**

* Use it in template databases when you want privileges to stay consistent
* Grant privileges *to it*, not to users
* Reach for it when handing out schema or function access

**Don't:**

* Try to grant it to users, since that always fails
* Expect it to reach across databases, since its scope is the current one
* Assume it carries privileges on its own, because it starts with none

## Conclusion

`pg_database_owner` is a small change with a clear payoff: it gives PostgreSQL a clean, dynamic way to tie privileges to whoever owns a database, and the privileges follow ownership automatically. If you're running multi-tenant setups or just want a `public` schema that isn't wide open, it makes privilege management simpler and your defaults safer.