Realtime: "must be owner of table messages" when setting up Authorization
Last edited: 9/26/2026
A migration that adds an RLS policy to realtime.messages fails:
ERROR: 42501: must be owner of table messagesCause#
realtime.messages is owned by an internal role, supabase_realtime_admin. The postgres role is not a member of it and is not a superuser.
Policies still work because of supautils, the extension that gives the postgres role its elevated permissions on a Supabase project. It lets postgres run create policy, alter policy, and drop policy on a fixed list of tables it does not own, and realtime.messages is on that list. The list covers policy statements only, so ALTER TABLE is still refused.
The failing statement is usually not the create policy. It's an ALTER TABLE earlier in the same migration:
alter table realtime.messages enable row level security;alter table realtime.messages add column ...;alter table realtime.messages owner to postgres;The first one is the common case. RLS is already enabled on realtime.messages, and Postgres checks ownership before it checks whether the setting would change, so the statement fails on every project.
A failed statement aborts the transaction, so Postgres skips everything after it, including the create policy. supabase db push runs each migration file in one transaction, so the file rolls back and nothing is written to supabase_migrations.schema_migrations.
Fix#
Remove the ALTER TABLE line. Keep the policy:
create policy "authenticated can read messages on room-1"on "realtime"."messages"for selectto authenticatedusing ( (select realtime.topic()) = 'room-1');Run it from the SQL editor or with supabase db push. Both connect as postgres.
To check that RLS is on, read the catalog instead of setting it:
select relrowsecurity from pg_class where oid = 'realtime.messages'::regclass;What doesn't work#
Granting the owning role fails, and support can't grant it either:
grant supabase_realtime_admin to postgres;-- ERROR: 42501: "supabase_realtime_admin" role memberships are reserved, only superusers can grant themRestarting the project changes nothing.
Wrapping the ALTER TABLE in a function or a do block changes nothing either. The ownership check still runs, and a security definer function owned by postgres is still not the table owner.
What postgres can do on realtime.messages#
The Yes rows are what supautils delegates, plus the privileges granted to postgres directly.
| Statement | Allowed |
|---|---|
create policy, alter policy, drop policy | Yes |
comment on policy | Yes |
select, insert | Yes |
grant select, grant insert to your own roles | Yes |
alter table in any form | No |
drop table | No |
Creating tables or functions in the realtime schema | No |
See Realtime Authorization for writing the policies.