Zum Inhalt springen

Sicherheitsgrundlagen

Supabase "permission denied for table": der fehlende Grant

Ab 30. Oktober antwortet eine neue Supabase-Tabelle mit "permission denied for table", bis du Zugriff erteilst. Der Grant aus der E-Mail ist die halbe Lösung.

Vlad Tkachenko9 Min. Lesezeit
Eine Reihe von Türen zu Datenbanktabellen. Die älteren stehen offen und zeigen erleuchtete Zeilen, die neueste am Ende ist zu.

Kurz gesagt

  • Ab dem 30. Oktober 2026 antwortet eine neue Tabelle in deinem Supabase-Projekt mit "permission denied for table", bis jemand Zugriff auf sie erteilt. Die Tabellen, die du schon hast, funktionieren genau so weiter wie heute.
  • Ein Grant entscheidet, ob eine Anfrage eine Tabelle überhaupt erreicht. Welche Zeilen sie zurückbekommt, entscheidet weiterhin Row Level Security. Wer anon Zugriff auf eine Tabelle ohne Regeln gibt, macht jede Zeile für jeden lesbar.
  • Die Änderung schließt nichts, was schon offen ist. Prüf heute, was ein Fremder lesen kann, und danach wieder nach jeder neuen Tabelle.

Wenn deine App auf Supabase läuft, hast du wahrscheinlich eine E-Mail zum 30. Oktober bekommen. Darin steht, dass sich für deine bestehenden Tabellen nichts ändert, und dann bekommst du drei SQL-Statements in die Hand gedrückt. Oder es ist schon November: Du hast Lovable, Bolt oder Cursor um eine neue Funktion gebeten, der neue Bildschirm bleibt leer, und irgendwo in der Konsole steht eine Meldung mit permission denied for table. Beides ist dieselbe Supabase-Änderung, nur von zwei Seiten des Datums aus gesehen.

Hier ist der Teil, den die E-Mail weglässt: Das SQL, das sie dir zeigt, ist nur die halbe Lösung. Führ diese Hälfte allein aus, auf der falschen Tabelle, und deine App läuft wieder, während die neue Tabelle ihre Zeilen jedem gibt, der danach fragt.

Was bedeutet "permission denied for table" in Supabase?

Es bedeutet, dass die Art von Besucher, die die Anfrage stellt, überhaupt keinen Zugriff auf diese Tabelle bekommen hat. Die Datenbank hat also abgelehnt, bevor sie sich auch nur eine Zeile angesehen hat.

Supabase ordnet jede Anfrage einer Rolle zu, also der Art von Besucher, von der sie kommt. anon ist jemand, der nicht angemeldet ist. authenticated ist jemand, der angemeldet ist. service_role ist dein eigener Servercode mit dem geheimen Schlüssel. Ein Grant ist die Anweisung, die einer dieser Rollen Zugriff auf eine Tabelle in Postgres gibt, der Datenbank, auf der Supabase läuft. Ohne Grant kein Zugriff, egal was du sonst geschrieben hast.

Fehlt der Grant, antwortet Supabase so, meist als 401 oder 403:

{
  "code": "42501",
  "message": "permission denied for table comments",
  "hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.comments TO anon;"
}

Der Hinweis ist der nützliche Teil. Er nennt die Rolle, die abgewiesen wurde, und genau das Statement, das sie hereinlassen würde.

Stell dir jede Tabelle als Raum vor. Der Grant ist die Tür, und für jede Rolle gibt es eine eigene Tür. Row Level Security, die Regeln pro Zeile, die du vielleicht schon kennst, entscheidet, welche Schubladen ein Besucher öffnen darf, wenn er drinnen ist. "Permission denied for table" heißt, dass jemand vor einer geschlossenen Tür steht. Bis zu deinen Regeln ist er nie gekommen.

Was ändert sich am 30. Oktober?

Neue Tabellen im public-Schema, dem Tabellenordner, den dein Builder benutzt, solange ihm niemand etwas anderes sagt, kommen ab dann mit geschlossenen Türen an.

Bisher hat Supabase bei jeder neuen Tabelle automatisch alle drei Türen geöffnet: Lesen, Hinzufügen, Ändern und Löschen, für anon, authenticated und service_role gleichermaßen. Eine Tabelle war von deiner App aus erreichbar, sobald sie existierte, und deine Row-Level-Security-Regeln waren das Einzige zwischen einem Fremden und ihren Zeilen. Das Changelog von Supabase nennt den Grund ohne Umschweife: Agenten und KI-Plattformen legen heute Tabellen an, ohne dass jemand die Änderung prüft, und die automatischen Grants haben Tabellen offengelegt, die "a developer forgot to protect", die also jemand zu schützen vergessen hatte.

DatumWas passiert ist oder passiert
28. April 2026Neue Projekte konnten die automatischen Grants beim Anlegen abwählen.
30. Mai 2026Der Verzicht auf automatische Grants wurde schrittweise Standard für neue Projekte.
30. Oktober 2026Auch bestehende Projekte bekommen sie nicht mehr.

Wenn dein Projekt nach Ende Mai angelegt wurde, funktioniert es vielleicht schon so, denn Supabase hat den neuen Standard in den Wochen nach diesem Datum nach und nach für neue Projekte eingeführt.

Tabellen, die am 30. Oktober existieren, behalten ihre Türen, auch eine, die für Fremde offen stand. Nur die Tabellen, die danach entstehen, beginnen mit geschlossener Tür.

Drei Details solltest du vor dem Stichtag kennen:

  • Nur das public-Schema. Storage und die Anmeldung haben ihre Tabellen in eigenen Schemas, storage und auth, und laut Supabase bleiben deren Grants und Voreinstellungen, wie sie sind.
  • Auch der geheime Schlüssel wird abgewiesen. Die automatischen Grants galten auch für service_role. Eine Edge Function (Servercode, den Supabase für dich ausführt), die deinen geheimen Schlüssel benutzt, bekommt deshalb bei einer neuen Tabelle denselben Fehler, bis service_role einen eigenen Grant hat.
  • Eine gelöschte und neu angelegte Tabelle ist eine neue Tabelle. Grants gehören zur Tabelle selbst und verschwinden mit ihr, wenn sie gelöscht wird. Baut dein Builder eine Tabelle neu, um sie zu ändern, beginnt die neu gebaute mit geschlossener Tür.

Geht meine App am 30. Oktober kaputt?

Nicht an diesem Tag. Sie geht kaputt, wenn zum ersten Mal etwas eine neue Tabelle anlegt, ohne auch den Grant anzulegen.

Für die meisten, die das hier lesen, ist dieses Etwas ihr Builder. Du bittest um einen Kommentarbereich. Der Builder schreibt eine Migration, also die Datei mit Datenbankänderungen, die er für dich ausführt, und die Migration legt eine Tabelle comments an. Schreibt er die Grants gleich mit, siehst du diesen Fehler nie. Tut er es nicht, zeigt der Kommentarbereich nichts an, oder das Speichern eines Kommentars scheitert, oder eine rote Meldung erscheint, je nachdem, wie deine App mit Fehlern umgeht. Jeder Bildschirm, den du schon hattest, läuft weiter.

Supabase veröffentlicht einen Agent Skill für KI-Coding-Tools, der den Grant-Schritt enthält. Ob dein Builder ihn benutzt, entscheidet dein Builder. Geh also sicherheitshalber davon aus, dass die nächste Tabelle, die er anlegt, mit geschlossener Tür ankommen kann.

Kann ich den GRANT aus der Fehlermeldung gefahrlos ausführen?

Erst wenn für die Tabelle Row Level Security eingeschaltet ist und eine Regel für sie existiert. Der Grant entscheidet, wer durch die Tür kommt. Welche Schubladen jemand öffnet, entscheidet er nicht.

Der Schlüssel, mit dem deine App ihre Anfragen an Supabase stellt, steckt in deiner App. Ein Grant an anon heißt also, dass jeder Besucher, angemeldet oder nicht, diese Tabelle jetzt nach Zeilen fragen darf. Mit einer Regel bekommt er die Zeilen, die die Regel erlaubt. Mit ausgeschalteter Row Level Security bekommt er jede Zeile der Tabelle, und an deiner App sieht nichts anders aus.

Die E-Mail zeigt drei Grants und hört auf. Das Changelog von Supabase zeigt drei Schritte und sagt, man solle "treat these three steps as a unit", sie also als Einheit behandeln:

-- 1. wer die Tabelle erreichen darf
grant select on public.orders to authenticated;
grant select, insert, update, delete on public.orders to service_role;

-- 2. die Regeln pro Zeile einschalten
alter table public.orders enable row level security;

-- 3. die Regel selbst
create policy "Customers read their own orders"
  on public.orders
  for select
  to authenticated
  using (auth.uid() = user_id);

In diesem Beispiel gibt es keine Zeile für anon, und das ist Absicht. Niemand, der abgemeldet ist, sollte eine Tabelle mit Bestellungen erreichen. Die Tür für Fremde bleibt also zu, und angemeldete Kunden bekommen nur den Lesezugriff, den ihr Bildschirm braucht. Die Regel grenzt das dann auf ihre eigenen Zeilen ein. Supabase selbst rät, jeder Rolle nur das Nötigste zu geben. Ein Grant an anon gehört auf eine Tabelle, deren Zeilen für alle gedacht sind, etwa die Kommentare unter einem öffentlichen Beitrag.

Der Grant entscheidet, ob eine Anfrage die Tabelle erreicht. Die Regeln dahinter entscheiden, wie viel sie mitnimmt. Eine offene Tür ohne Regeln dahinter gibt die ganze Tabelle heraus.

Wenn du sehen willst, auf welcher Seite dieses Bildes deine Tabellen stehen, stellt unser kostenloser Scan deiner Live-App die Frage, die ein Fremder stellen würde, zählt die Zeilen, die er bekäme, ohne eine davon abzurufen, und braucht dafür etwa 20 Sekunden ohne Konto: scanne deine App.

Warum die Row-Level-Security-Lösungen diesen Fehler nicht berühren

Weil zuerst der Grant geprüft wird. Eine Anfrage, die an der Tür abgewiesen wird, erreicht deine Regeln nie. Die Regeln zu ändern, ändert also nichts am Fehler.

Das ist wichtig, weil der Code geteilt ist. 42501 gibt Postgres auch zurück, wenn Row Level Security ein Speichern ablehnt, wie bei new row violates row-level security policy. Ein Assistent, der sich nur am Code orientiert, greift womöglich zu den Lösungen, die zu jenem Fehler gehören: Row Level Security ausschalten oder eine Regel mit using (true) hinzufügen, die alle durchlässt. Keine von beiden lässt diesen Fehler verschwinden. Beide bleiben zurück, wenn der Grant schließlich kommt, und dann steht die Tür offen vor Schubladen ohne Schloss.

Die Worte in der Meldung unterscheiden die beiden, auch wenn die Nummer es nicht tut:

Die Meldung lautetWelches Schloss abgelehnt hatWas es behebt
permission denied for tabledie Tür (der Grant)ein Grant für die Rolle, die der Hinweis nennt
new row violates row-level security policydie Regelneine Policy, die diese Zeile erlaubt
kein Fehler, und die Liste ist leerdie Regelneine Lese-Policy für diese Rolle

Was der 30. Oktober nicht behebt

Jede Tabelle, die du schon hast. Sie behält genau den Zugriff, den sie heute hat, auch eine Tabelle, die ein Fremder in diesem Moment lesen kann.

Die Änderung betrifft Tabellen, die es noch nicht gibt. Bisher kam jede neue Tabelle mit offenen Türen an. Eine App, die vor dem 30. Oktober gebaut wurde, kann also eine haben, bei der nie jemand die Schlösser angebracht hat: Row Level Security nie eingeschaltet, oder eingeschaltet unter einer Regel, die alle hereinlässt. Der 30. Oktober lässt diese Räume genau so, wie sie sind.

Drei Stellen zeigen dir, wo du stehst:

  1. Die Einstellungsseite der Data API, die in der E-Mail verlinkt ist. Im Dashboard liegt sie unter Integrations, dann Data API, und sie listet auf, welche deiner Tabellen überhaupt erreichbar sind.
  2. Der Security Advisor, der laut Supabase die Tabellen auflistet, die du vor der Änderung prüfen solltest.
  3. Der Blick von außen. Keine der beiden ersten Stellen sagt dir, was ein Fremder zurückbekommt. Dafür fragst du deine Live-App so, wie ein Fremder es tun würde, und genau das macht unser Scan.

Wie Reeve die Tabellen im Blick behält, die du hinzufügst

Nach dem 30. Oktober ist jede Tabelle, die dein Builder hinzufügt, eine neue Entscheidung darüber, wer durch die Tür kommt. Reeve prüft die Antwort von außen, und Monitor prüft sie immer wieder.

  • Der kostenlose Scan fragt jede Tabelle, die deine App nennt, wie viele Zeilen ein Besucher ohne Login bekäme, liest die Zahl und hört dort auf, ohne eine Zeile abzurufen. Etwa 20 Sekunden, kein Konto: scanne deine App.
  • Reeve Monitor führt jede Stunde alle neun Prüfungen für bis zu drei Apps aus und schickt dir an dem Tag eine E-Mail, an dem sich deine Note verschlechtert. Ein Deployment, das etwas geöffnet hat, wartet also nicht darauf, dass du nachsehen kommst.
  • Care führt dieselben Prüfungen aus und bewahrt eine verschlüsselte Kopie deiner Supabase-Datenbank außerhalb deines Supabase-Kontos auf. Baut die Lösung eines Assistenten eine Tabelle neu, gibt es eine Kopie, zu der du zurückkehren kannst. Wie die Kopie entsteht und zurückgespielt wird.

Was jeder Tarif umfasst, steht auf der Preisseite.

Was du vor dem 30. Oktober tun solltest

Was zu tun ist

  • Lass die Tabellen, die du schon hast, in Ruhe, wenn du nur willst, dass deine App weiterläuft. Sie behalten ihre Grants.
  • Bitte deinen Builder, bei jeder neuen Tabelle den Grant, enable row level security und eine Policy in dieselbe Migration zu schreiben, als eine einzige Änderung.
  • Wenn der Fehler auftaucht, lies, welche Rolle der Hinweis nennt. anon heißt jeder Besucher deiner App.
  • Gib anon auf einer Tabelle nichts, solange Row Level Security nicht an ist und keine Regel existiert. Tabellen mit Menschen oder Bestellungen brauchen meist überhaupt keinen Grant für anon.
  • Lehne jede Lösung ab, die Row Level Security ausschaltet oder using (true) hinzufügt, um einen Berechtigungsfehler zu beseitigen. Keine von beiden berührt ihn.
  • Prüf, was ein Fremder aus den Tabellen lesen kann, die du schon hast. Der 30. Oktober lässt sie, wie sie sind.

Fang mit der Tabelle an, die ein Fremder am liebsten lesen würde, meist die mit Menschen darin, und scanne deine App, um zu sehen, was sie heute herausgibt.

FAQ

Hört meine Supabase-App am 30. Oktober auf zu funktionieren?

Nein. Jede Tabelle, die am 30. Oktober existiert, behält den Zugriff, den sie hat, und Supabase hat bestätigt, dass diese Grants nicht entzogen werden. Was sich ändert, ist die nächste Tabelle, die nach diesem Datum angelegt wird. Sie ist für deine App zunächst unerreichbar, bis jemand Zugriff auf sie erteilt. Das Erste, was kaputtgeht, ist also die erste neue Funktion, die eine neue Tabelle braucht.

Was bedeutet "permission denied for table" in Supabase?

Es bedeutet, dass die Art von Besucher, die die Anfrage stellt, überhaupt keinen Zugriff auf diese Tabelle bekommen hat. Deine Datenbank hat also abgelehnt, bevor sie sich auch nur eine Zeile angesehen hat. Die Meldung kommt von Postgres, der Datenbank, auf der Supabase läuft, mit dem Code 42501, und erreicht deine App meist als 401 oder 403. Supabase hängt einen Hinweis an, der genau das GRANT-Statement nennt, das diesen Besucher hereinlassen würde.

Kann ich das GRANT-Statement aus der Fehlermeldung gefahrlos ausführen?

Erst wenn für die Tabelle Row Level Security eingeschaltet ist und eine Regel für sie existiert. Ein Grant an anon erlaubt jedem Besucher deiner App, die Tabelle nach Zeilen zu fragen, denn der Schlüssel, mit dem diese Anfragen gestellt werden, steckt in deiner App. Mit einer Regel bekommen sie die Zeilen, die die Regel erlaubt. Ohne Regel und mit ausgeschalteter Row Level Security bekommen sie alle.

Betrifft die Änderung Storage, die Anmeldung oder meine Edge Functions?

Storage und die Anmeldung liegen in eigenen Schemas, storage und auth, und laut Supabase bleiben deren Grants und Voreinstellungen, wie sie sind. Bei Edge Functions ist es anders. Eine, die deinen geheimen Schlüssel benutzt, braucht für jede neue Tabelle trotzdem einen Grant, denn die wegfallenden Standard-Grants galten auch für service_role und nicht nur für die zwei Rollen, die deine Besucher benutzen.

Kann ich das alte Verhalten wieder einschalten?

Supabase dokumentiert einen Weg dafür, als Einstellung auf der Data-API-Seite im Dashboard oder als SQL, und rät davon ab. Ist es an, ist jede neue Tabelle für jeden Besucher erreichbar, sobald sie existiert, und Row Level Security ist das Einzige, was zwischen einem Fremden und ihren Zeilen steht. So hat jedes Projekt vor der Änderung funktioniert.

Geschrieben von

Vlad Tkachenko

Gründer, Reeve

Ich schaue mir den ganzen Tag Apps an, die mit Lovable, Bolt, v0, Cursor und Replit gebaut wurden, und die kurze Liste von Fehlern, die darin immer wieder auftauchen.

Mehr über den Autor

Weiterlesen

Alle Artikel

Unsicher, wie es um deine eigene App steht?

Starte einen kostenlosen Scan und erhalte in rund 20 Sekunden eine verständliche Note von A bis F. Ohne Konto, ohne Karte.

App kostenlos scannen

Automatisierte externe Prüfung, kein vollständiges Audit. Das Fehlen von Funden ist keine Garantie für Sicherheit.