Key takeaways
- Application-level tenant filters fail the first time a developer forgets one. Row-level security moves the rule into the database so it applies to every query.
- Row-level security has sharp edges: table owners and superusers bypass it unless you force it, and connection pooling can carry one tenant's setting into another request.
- Per-tenant encryption keys do not replace access control. They add a second layer, enable per-tenant revocation and make audit trails clearer.
- Test isolation like a security feature: write cross-tenant tests that must fail, and run them on every release.
Start with the answer: use two layers. First, make the database refuse to return another tenant's rows, with PostgreSQL row-level security. Second, encrypt sensitive data under keys scoped to each tenant, so that one bug or one stolen backup does not expose everyone. Neither layer works alone, and both need tests.
Why the application filter is not enough
The common pattern is a tenant identifier column on every table and a where clause in every query. It works until someone writes a report query, a background job or an admin screen and forgets the clause. In the OWASP Top 10, broken access control is the leading category for good reason. An isolation rule that depends on every developer remembering it every time will eventually fail. The goal is a design where forgetting is safe.
Layer one: row-level security in PostgreSQL
With row-level security, you enable it on a table and define policies. A policy is an expression the database checks for each row. A typical policy says a row is visible only when its tenant identifier equals the tenant set for the current session. The PostgreSQL documentation describes policies for reading, inserting, updating and deleting, and explains that without a policy, a table with security enabled denies access by default.
The application sets the current tenant at the start of each request, from the authenticated identity and never from user input, and every query then runs under that boundary. A forgotten filter returns nothing instead of everything.
Know the edges, because they are where leaks happen.
- Table owners and roles with the bypass attribute skip policies. Superusers always do. The application should connect as a role that owns nothing and cannot bypass. For owners, the documentation describes a force option that applies policies to them too.
- Session settings and pooling. If a pooler reuses connections across requests, a tenant setting left from the previous request is a leak. Set it per transaction and reset it, and test with the pooler on.
- Views run with their owner's rights by default, which can skip the policy. Check how each view is defined.
- Foreign keys and unique constraints can reveal that another tenant's row exists. Include the tenant column in keys where it matters.
- Performance. The policy expression runs on every query, so index the tenant column and look at query plans on large tables.
Row-level security is one model. Some teams prefer a schema or a database for each tenant, which isolates harder and costs more to operate at scale. A shared table with policies is the cheapest to run. The right choice depends on the number of tenants, regulatory pressure and how large the biggest tenant is.
Layer two: per-tenant encryption keys
Encryption does not stop a logged-in query from returning data the application is allowed to read. What it does is limit what a stolen disk, a leaked backup or a careless snapshot export reveals, and it lets you control decryption for each tenant separately. The standard design is envelope encryption: a data key encrypts the data, and a key in a key management service encrypts the data key. AWS Key Management Service documents this pattern, and the keys never leave the service unencrypted.
For tenants, there are two reasonable shapes. One is a separate KMS key for each tenant, which gives clean revocation and separate audit entries, at the cost of key counts and quotas. The other is a shared key with a tenant identifier in the encryption context. The encryption context is extra authenticated data bound to the ciphertext: decryption fails unless the same context is supplied, and it appears in the key service's logs. Key policies and grants can then tie use of the key to the tenant's own role. AWS describes tenant isolation approaches in its SaaS architecture guidance, including the trade-offs between pooled and siloed models.
Plan for the unglamorous parts: key rotation, what happens when a tenant leaves and asks for deletion, how backups interact with deleted keys, and who can change key policies. A tenant key you can schedule for deletion is a strong offboarding story, but only if you have tested what breaks.
Prove it with tests
- Create two test tenants and write tests that try to read, update and delete the other tenant's data through every path: the API, exports, search, background jobs and admin tools. Each must fail.
- Run the tests as the application role, not as an owner.
- Check logs and error messages for tenant data and identifiers.
- Have a security engineer attack the boundary before launch and after major changes.
Our team designs and reviews multi-tenant systems, and our cybersecurity team tests isolation under written authorization. If you are building or inheriting a SaaS platform, start with our Tailored Software or Cybersecurity service.
Sources
- PostgreSQL documentation: Row Security Policies
- PostgreSQL documentation: CREATE POLICY
- AWS Key Management Service: Concepts
- AWS Key Management Service: Encryption context
- AWS whitepaper: SaaS Architecture Fundamentals, Tenant isolation
- OWASP Top 10:2021, A01 Broken Access Control
This article is general information, not legal advice. Your obligations and the right steps depend on your systems, contracts and the laws that apply to you. Last reviewed .
Keep reading
Next · InfrastructureSQL Server Always On vs. Log Shipping vs. Backups: What Each ProtectsAvailability groups keep you running through a server failure. Log shipping gives you a delayed warm copy. Backups let you go back in time. Only backups protect against a bad delete or ransomware, so you need them even if you have the other two.7 min read- Replacing Legacy Business Software with Custom Software: When It Pays and How to Test the Idea in Two Weeks9 min
- Bringing ALM and CECL In-House: Models, Data and Model Risk11 min
Need help with this?
Software built around your business in weeks, and you own the code.
Tailored Software