Mandantenfähigkeit: Daten in SaaS-Plattformen sauber trennen
Mandantenfähige Software trennt die Daten mehrerer Kunden auf einer gemeinsamen Plattform, entweder über eine Mandantenspalte in gemeinsamen Tabellen, über getrennte Schemas oder über eine eigene Datenbank je Kunde. Welches Modell passt, hängt von Kundenzahl, Anpassungswünschen und Anforderungen der Kunden an die Trennung ab.
Wer eine Plattform für mehrere Kunden baut, trifft die Entscheidung über die Trennung der Daten am Anfang, und sie ist später nur mit viel Aufwand zu ändern. Sie bestimmt, wie teuer der hundertste Kunde im Betrieb ist, wie ein Großkunde mit eigener IT-Prüfung überzeugt wird und was passiert, wenn ein einziger Filter im Code fehlt. Für SaaS-Portale und Plattformen gehört diese Frage deshalb ins erste Architekturgespräch, nicht in den ersten Engpass.
Begriff
Was Mandantenfähigkeit bedeutet
Mandantenfähigkeit heißt: Eine Installation der Software bedient mehrere Kunden, die Mandanten, und jeder sieht nur seine eigenen Daten, Nutzer und Einstellungen. Im Englischen heißt das Multi-Tenancy, ein Mandant ist ein Tenant.
Das Gegenmodell ist die Einzelinstallation: Jeder Kunde bekommt eine eigene Kopie der Anwendung auf eigenem Server. Das ist sauber getrennt, aber jedes Update muss auf jede Kopie, und spätestens bei zwanzig Kunden laufen die Versionen auseinander. Mandantenfähige Software dagegen spielt eine Codebasis für alle aus. Ein Fehler wird einmal behoben, eine neue Funktion steht allen zur Verfügung, und ein neuer Kunde ist ein Datensatz statt eines Servers.
Dafür muss die Software die Trennung selbst leisten, die bei Einzelinstallationen der Server übernimmt. Jede Abfrage, jeder Export, jede Datei und jeder Hintergrundjob muss wissen, für welchen Mandanten er arbeitet.
Modelle
Drei Modelle: gemeinsame Tabellen, Schema, eigene Datenbank
In der Praxis haben sich drei Modelle durchgesetzt, dazu Mischformen.
Gemeinsame Tabellen mit Mandantenspalte
Alle Kunden teilen sich dieselben Tabellen, jede Zeile trägt die Kennung ihres Mandanten. Das ist im Betrieb am günstigsten: eine Datenbank, eine Migration, ein Backup. Auswertungen über alle Mandanten, etwa für die eigene Abrechnung, sind eine Abfrage. Das Risiko liegt darin, dass die Trennung an jeder Abfrage hängt. Fehlt die Bedingung einmal, sieht ein Kunde die Daten eines anderen.
Ein Schema je Mandant
PostgreSQL kennt Schemas, getrennte Namensräume innerhalb einer Datenbank. Jeder Mandant bekommt seine eigenen Tabellen, die Anwendung wählt pro Anfrage das passende Schema. Die Trennung ist stärker, weil eine vergessene Bedingung nicht mehr in fremde Daten führt. Das Risiko verschiebt sich aber nur: Welches Schema gilt, bestimmt der Suchpfad (search_path) der Datenbankverbindung. Wird er falsch gesetzt oder bleibt er in einer wiederverwendeten Verbindung vom vorherigen Mandanten stehen, etwa in einem langlebigen Worker oder einem Verbindungspool, liest die nächste Anfrage im fremden Schema. Der Suchpfad gehört deshalb bei jeder Anfrage und jedem Job neu gesetzt und geprüft. Dafür laufen Migrationen für jedes Schema einzeln, und bei einigen Hundert Mandanten dauert ein Update merklich länger.
Eine Datenbank je Mandant
Jeder Kunde hat seine eigene Datenbank. Das ist die stärkste Trennung innerhalb einer gemeinsamen Anwendung: Backups und Wiederherstellung je Kunde, Speicherort nach Kundenwunsch, Löschung durch Entfernen einer Datenbank. Der Betrieb ist am aufwendigsten. Verbindungen, Migrationen, Überwachung und Auswertungen über alle Kunden müssen für viele Datenbanken funktionieren.
Welche Datenbank für welches Modell taugt, beeinflusst die Wahl mit. Schemas und zeilenbasierte Sicherheit sind Stärken von PostgreSQL, wie der Beitrag MySQL oder PostgreSQL zeigt.
Fallen
Sicherheitsfallen bei der Trennung
Die meisten Lecks zwischen Mandanten entstehen nicht in der Hauptansicht, die jeder testet, sondern an den Rändern der Anwendung. Diese Stellen gehören in jede Prüfung einer mandantenfähigen Anwendung:
Abfragen am Modell vorbei: In Laravel sorgt ein globaler Scope dafür, dass jede Eloquent-Abfrage automatisch nach Mandant filtert. Abfragen über den Query Builder oder rohes SQL kennen diesen Scope nicht. Ein Bericht, der aus Geschwindigkeitsgründen direkt auf die Tabelle zugreift, liefert dann Zahlen aller Kunden.
Hintergrundjobs: Ein Job in der Warteschlange läuft ohne Anfrage und ohne angemeldeten Nutzer. Wird der Mandant dort aus der Sitzung gelesen, ist er leer, und der Scope filtert nichts oder das Falsche. Der Mandant muss mit dem Job übergeben werden. Laravel bietet dafür den Context, der Werte aus der Anfrage an Jobs in der Warteschlange weiterreicht.
Cache: Ein Zwischenspeicher-Eintrag „Dashboard-Zahlen“ ohne Mandantenkennung im Schlüssel zeigt dem zweiten Kunden die Zahlen des ersten.
Dateien: Uploads gehören in Verzeichnisse je Mandant, und der Download prüft die Zugehörigkeit, nicht nur, ob jemand angemeldet ist.
Eindeutigkeit: Eine Rechnungsnummer ist je Mandant eindeutig, nicht global. Ein eindeutiger Index ohne Mandantenspalte führt dazu, dass Kunde B die Nummer 2026-001 nicht vergeben kann, weil Kunde A sie schon hat. Das ist kein Leck, verrät aber, dass es andere Kunden gibt.
Administratoren: Werkzeuge für den eigenen Support schalten den Scope bewusst ab. Diese Stellen gehören in eine eigene, gesondert geschützte Oberfläche.
Wer PostgreSQL nutzt, kann zusätzlich Row Level Security einsetzen. Dann filtert die Datenbank selbst, auch wenn die Anwendung eine Bedingung vergisst. Laut PostgreSQL-Dokumentation umgehen allerdings Superuser, Rollen mit dem Attribut BYPASSRLS und normalerweise auch der Eigentümer einer Tabelle die Regeln. Verbindet sich die Anwendung mit dem Benutzer, der die Tabellen per Migration angelegt hat, wirkt die Regel nicht. Abhilfe schafft ein eigener Datenbankbenutzer für die Anwendung ohne Eigentumsrechte oder die Option FORCE ROW LEVEL SECURITY an der Tabelle.
Für automatisierte Tests empfehlen wir eine eigene Testart, die auch ein Prüfer ohne Programmierkenntnisse nachvollziehen kann. Sie legt zwei Mandanten an, schreibt Daten für Mandant A und prüft, dass Mandant B über Oberfläche, Schnittstelle, Export und Suche nichts davon sieht.
Anpassungen
Mandantenspezifische Anpassungen ohne Code-Wildwuchs
Große Kunden wünschen sich Anpassungen: eigenes Logo, eigene Felder, eine Anbindung an ihr ERP, eine Anmeldung über das eigene Unternehmenskonto. Die Gefahr ist, dafür Sonderwege in den Code zu schreiben, bis jede Funktion mit „wenn Kunde X“ beginnt.
Drei Wege halten das beherrschbar:
Konfiguration statt Verzweigung: Farben, Logos, Texte, Pflichtfelder und Funktionsschalter liegen als Einstellungen beim Mandanten. Der Code fragt „ist die Funktion für diesen Mandanten aktiv“, nicht „ist das Kunde X“.
Erweiterungspunkte: Kundenspezifische Logik, etwa der Export in ein bestimmtes ERP, steckt in eigenen Klassen hinter einer festen Schnittstelle. Der Kern der Anwendung kennt nur die Schnittstelle.
Zusatzfelder als Daten: Eigene Felder je Mandant lassen sich in einer JSON-Spalte speichern, statt für jeden Kunden Spalten anzulegen.
Ein Beispiel aus unserem Portfolio ist Cardeleine, eine Multi-Mandanten-Plattform für digitale Visitenkarten, die wir seit November 2021 in drei Codebasen entwickeln: API, Browser-App und native App. Dort gibt es Anpassungen für Großkunden aus Beauty, Finance und Beratung, darunter Anbindungen an SharePoint, Azure und Personio und SAML2-SSO für Großkunden. Solche Anbindungen bleiben nur wartbar, wenn sie als abgegrenzte Bausteine neben dem gemeinsamen Kern stehen.
Größe
Welches Modell zu welcher Größe passt
Eine grobe Orientierung, abgeleitet aus Betriebsaufwand und Stärke der Trennung der drei Modelle. Sie ersetzt nicht den Blick auf Ihren Fall:
Viele kleine Kunden mit gleichen Funktionen, etwa ein Werkzeug für Handwerksbetriebe oder Praxen: gemeinsame Tabellen mit Mandantenspalte, abgesichert durch globale Scopes, Tests mit zwei Mandanten und bei PostgreSQL zusätzlich Row Level Security.
Einige Dutzend Geschäftskunden mit eigenen Anforderungen: gemeinsame Tabellen oder Schemas, je nachdem, wie oft Kunden einzeln wiederhergestellt oder exportiert werden müssen.
Wenige große Kunden mit Prüfpflichten, etwa aus Finanzwesen oder Gesundheit: eine eigene Datenbank je Kunde, gegebenenfalls auf eigenem Server in Deutschland.
Mischformen sind möglich und verbreitet: Die meisten Kunden teilen sich Tabellen, ein Großkunde bekommt eine eigene Datenbank. Das setzt voraus, dass die Anwendung den Mandanten von Anfang an sauber auflöst, an einer Stelle, über eine Middleware, die für jede Anfrage den Mandanten und die passende Verbindung bestimmt. Ein späterer Wechsel des Modells ist dann eine Datenmigration, kein Umbau der ganzen Anwendung. Wir schätzen dafür mit sauberer Mandantenauflösung eher Tage bis wenige Wochen, ohne sie oft Monate, weil jede Abfrage geprüft werden muss.
Kurz beantwortet
Häufige Fragen
-
Sie begrenzt den Schaden eines Programmierfehlers, weil eine vergessene Filterbedingung nicht in fremde Daten führt. Gegen falsch zugeordnete Verbindungen, offene Dateiablagen oder geteilte Cache-Einträge schützt sie nicht. Sicher wird eine Plattform durch die Summe aus Modell, Tests und Prüfung der Ränder, nicht durch das Modell allein.
-
Das gelingt, wenn die Anwendung den Mandanten an einer zentralen Stelle bestimmt und Abfragen nicht über den ganzen Code verstreut filtern. Dann bleibt der Wechsel im Wesentlichen eine Datenmigration. Fehlt diese zentrale Stelle, berührt der Wechsel fast jede Datei und wird zum eigenen Projekt.
-
Als Anbieter verarbeiten Sie die Daten Ihrer Kunden meist im Auftrag, dafür braucht es einen Auftragsverarbeitungsvertrag nach Art. 28 DSGVO. Art. 32 verlangt technische und organisatorische Maßnahmen, die die Vertraulichkeit auf Dauer sicherstellen, wozu die Trennung der Mandanten zählt. Nach Art. 28 Abs. 3 lit. g regelt der Vertrag auch, dass die Daten nach Ende der Leistung gelöscht oder zurückgegeben werden. Technisch heißt das: Export und Löschung je Mandant, ohne andere Kunden zu berühren.
Plattform mit sauberer Trennung planen
Wir klären mit Ihnen Kundenzahl, Anpassungswünsche und Prüfpflichten und schlagen das passende Mandantenmodell vor, bevor die erste Tabelle entsteht.
Nachweise
Quellen und Stand
Stand: 09.07.2026. Funktionen laut Dokumentation von PostgreSQL und Laravel. Die Hinweise zur DSGVO beschreiben die Rechtslage zu diesem Datum und ersetzen keine Rechtsberatung.
OWASP Cheat Sheet Series: Insecure Direct Object Reference Prevention
Verordnung (EU) 2016/679 (DSGVO), Art. 28 und Art. 32, EUR-Lex
Weiterlesen:
OWASP Top 10 2025 vom 12.10.2026: Der Test mit fremden Datensatz-Nummern prüft dieselbe Trennung aus Sicht eines Angreifers.
Artikel teilen