Multi-Tenant Databases and AI: Don't Forget org_id
AI SQL on a multi-tenant Postgres DB often drops the tenant filter. How to prompt for org_id/workspace_id, use views, and avoid cross-tenant counts in Claude or Cursor.
SaaS Postgres is usually multi-tenant: org_id, workspace_id, or account_id on the important rows.
Ask “how many orders last week?” without naming the org, and you may get every tenant summed. Valid SQL. Wrong answer. Sometimes a privacy issue.
Live access doesn’t fix it. Soft deletes and status enums are in metric traps; this is the tenant filter.
The failure mode
You meant: orders for org_id = 42.
The model ran: SELECT COUNT(*) FROM orders WHERE created_at > ….
Or it joined users across all orgs while you were debugging one customer ticket.
Support and admin-UI gaps make this worse — people paste one email and forget the rest of the tenant key.
Prompt rules that help
Put this above tenant-aware questions:
This database is multi-tenant.
Every query on tenant data MUST filter by org_id (or workspace_id —
confirm the column name from the schema).
If I don't give an org id, ask for it — don't count all tenants.
Show SQL every time.
Ticket-shaped ask:
org_id: 42
(or: resolve org from email <x> then filter everything by that org)
Count open subscriptions. Filter by org_id. Show SQL.
Exploration:
List tables that have org_id / workspace_id / account_id.
For orders, show an example COUNT grouped by org_id (top 5)
so we can see the grain — then stop.
Stronger than prompts: views
Create a view (or use staging data) that already encodes the tenant:
CREATE VIEW support_orders_org_42 AS
SELECT * FROM orders WHERE org_id = 42;
Point the allowlist at the view, not orders. Clumsy for many orgs; fine for a support break-glass or a demo tenant.
Better long-term: SELECT-only user that only has access to tenant-scoped views you control.
RLS caveat (Supabase especially)
Service role bypasses RLS. Connecting Claude with the service role means “see all tenants” unless you filter in SQL. Details: Connect Claude to Supabase.
If you need RLS to apply, you need a role and session setup that actually sets the tenant — not the bypass key.
Verify
- Known count for org A
- Ask AI for that count with org A in the prompt
- Ask again without org id — model should ask, not return the global total
- Read the SQL
When global counts are OK
Internal analytics on purpose: “signups across all orgs this week.” Say all tenants in the prompt so it’s intentional. Don’t mix that thread with a single-customer support lookup.
Make the model ask for org_id, or don’t hand it the raw table.
Staging + allowlist: mcpserver.design (7-day Solo trial).
Related reading:
- Why AI Gets 'Active Users' Wrong — other definition bugs
- Customer Support + AI Database — ticket lookups
- AI Chat vs Admin UI — one-customer questions
- Don't Give Your AI Access to Every Table — views and allowlists
- How to Verify AI Answers About Your Database — catch global counts