AAI Agentic Handbook
Security & Tenancy

Multi-tenancy

Senior levelReviewed Oct 2026In 4 interview questionsIn 2 posts

Serving many customers from shared infrastructure while keeping their data, quotas and performance isolated. Isolation tier is a cost vs risk choice.

In plain English

A multi-tenant system serves many customers (tenants) from the same software and often the same databases. Each customer must only ever see their own data, and one customer's heavy use shouldn't slow down the others. You can isolate tenants a lot (separate databases each, expensive) or a little (one shared database with a tenant id on every row, cheap but one bug away from a leak). Most products mix the two by customer size.

Analogy

An apartment building: tenants share the walls, plumbing and lift, but each has their own locked door and their own water meter.

Common pitfall

Isolating the database but not the caches. A semantic cache keyed only on the question text serves tenant A's answer, with tenant A's data in it, to tenant B asking the same question.

How it actually works

Three tiers: pooled (shared tables/index, tenant_id on every row, filtered on every query), bridge (shared cluster, separate namespace, schema or collection per tenant: Pinecone namespaces, Qdrant payload partitions with is_tenant, Postgres schema per tenant), silo (dedicated database or cluster per tenant). In pooled Postgres, enforce isolation with Row-Level Security rather than trusting every query: CREATE POLICY ... USING (tenant_id = current_setting('app.tenant_id')::uuid), set via SET LOCAL inside each transaction (critical with PgBouncer transaction pooling), and FORCE ROW LEVEL SECURITY because table owners bypass RLS otherwise. For vector search, filter by tenant inside the ANN search (pre-filter), not after top-k, or small tenants get empty results. Caches are a classic leak: every Semantic cache and prompt-cache key must include the tenant id. Isolation also means performance (Noisy neighbour), keys (per-tenant encryption for regulated customers), and data residency. Put tenant id in every log, trace and metric so you can answer 'what did tenant X see?'

What I'd ship on day one

Pooled Postgres with RLS (FORCE ROW LEVEL SECURITY, SET LOCAL app.tenant_id per transaction); vector store with tenant partitioning (Qdrant is_tenant payload index, Pinecone namespaces, or a tenant_id filter in pgvector with RLS); tenant id in every cache key, log, trace and metric; per-tenant rate limits; silo tier for regulated customers; cross-tenant test suite in CI.

Worked example

A B2B legal-contracts SaaS has 1,800 tenants. 1,750 small firms are pooled in one Postgres cluster with RLS and a shared Qdrant collection partitioned by tenant_id (is_tenant: true). 45 mid-size firms get their own Qdrant collection. 5 enterprise banks are siloed: dedicated cluster in-region, customer-managed KMS keys, separate model API keys. A CI test runs every API endpoint as tenant A and asserts zero rows from tenant B.

In the interview

I'd default to pooled with database-enforced isolation (Postgres RLS, tenant-partitioned vector collections, tenant id in every cache key) and offer silo as a priced tier for regulated customers. The follow-up: 'how do you prove isolation?' Automated cross-tenant tests on every endpoint, RLS so a missing WHERE clause fails safe, and tenant id on every trace for audits.

TierIsolationCost/tenantUse for
Pooled + RLSrow/filterlowestSMB, free tier
Bridgenamespace/collectionmediummid-market
Silodedicated clusterhighestregulated, residency
Mix tiers by customer segment; enforce isolation in the store, not only in app code.

Numbers worth knowing

Pooled vs silo infra cost
~10–100× cheaper per small tenanta dedicated cluster has a fixed floor regardless of data size
RLS query overhead
low single-digit % on indexed tenant_idpolicy predicate uses an index; can be much worse if it calls a function per row
Post-filter failure
0 results for a tenant with <1% of vectorstop-k=10 over the whole index, then filtered

How to decide

WhenDo this
Many small tenantsPooled with RLS and filter-in-search.
Tenant needs residency, own keys or audit isolationSilo, priced accordingly.
One tenant's data >10% of a shared indexMove it to its own collection (bridge).
Any shared cacheTenant id in the key, always.

Cost maths

Pooled: one 3-node vector cluster at ~$1,500/month serving 1,750 tenants ≈ $0.86/tenant/month. Silo: the smallest production-grade dedicated cluster (~$600–1,000/month) per tenant. Price silo as an enterprise add-on at a margin over that floor; a single cross-tenant leak in pooled mode costs far more in contracts and regulatory exposure, which is why the enforcement must be in the database.

Operating it

Time to scale up when…
  • One tenant >10% of queries or storage: promote to bridge or silo
  • Enterprise prospects asking for residency or customer-managed keys
  • Filtered ANN latency for small tenants degrading: add tenant-aware partitioning
What to monitor
  • Cross-tenant test suite in CI and a nightly prod canary: alert on any cross-tenant row
  • Queries executed without tenant context set (RLS denial count): alert >0 unexpected
  • Per-tenant share of QPS and storage: alert when one tenant >10%

When it goes wrong

What users saw

A tenant's support agent saw an answer that quoted another company's contract terms.

How it was caught

Customer report; traces showed the answer served from the semantic cache, originally generated for a different tenant.

Root cause

Retrieval was tenant-filtered and Postgres had RLS, but the semantic cache key was hash(normalised_question), with no tenant id.

Fix

Tenant id and ACL hash added to every cache key, cache flushed, cross-tenant tests extended to caches, and incident disclosed to both tenants.

Sources

  1. Row Security Policies — PostgreSQL, 2025docs
  2. Implement multitenancy — Pinecone, 2025docs
  3. OWASP Top 10 for LLM Applications 2025 — OWASP, 2025spec

Check yourself

Three questions. Every option is explained once you answer.

1ConceptWith PgBouncer transaction pooling, why set the tenant via SET LOCAL inside each transaction?
2ScenarioAn enterprise tenant requires data residency and its own encryption keys. Which isolation tier?
3CalculationOne $1,500/month vector cluster serves 1,750 pooled tenants. What is the infra cost per tenant?