Multi-tenant software can start with a TenantId column: filter every query by it and let many customers or locations share one application. The larger design job is deciding who may see each customer record, invoice, work order, document and integration credential, and it gets harder when one user works across tenants or a corporate administrator needs visibility across all of them.
When the tenant is not the customer account
In a simple SaaS product a tenant is one customer account. Business software can draw the boundary elsewhere. In a property-management application, for example, the paying customer may be a management company while the working boundary is a building or an assigned property manager. A regional manager needs roll-up reporting across buildings; a building manager should see maintenance requests and vendor invoices for assigned properties only.
The design has to name how each kind of record behaves. Some records belong to one tenant. Some are shared templates. Some roll up to a parent organization for reporting but are editable only by the local team. Some should never cross the boundary, even for support staff, without an audit entry. Drawing that model before the screens multiply lets new controllers, reports and background jobs inherit the rules from one place.
Where tenant scope leaks
Tenant scope needs to be passed in explicitly and checked. SQL Server and Azure SQL Database support row-level security, which can restrict the rows a query returns to one tenant, for example using a tenant value the application sets in session context. It applies to queries that reach the database. A cache, a search index or a file export built outside the database needs its own tenant key and its own tests.
A test of the main screens with two tenants in the sample data does not exercise the paths that run outside a web request: a cache entry keyed by customer number without the tenant, so the second tenant to load a page sees the first tenant's figures; a search index built across all tenants and queried without a tenant filter; a background job that processes tenants in a loop and retries a webhook with the credential of the last tenant it loaded.
Shared database, separate schemas, or a database per tenant?
Microsoft's SaaS tenancy patterns guide for Azure SQL Database lays out the trade-off. A multi-tenant database generally has the lowest cost per tenant and makes cross-tenant reporting simple. The guide says this model sacrifices tenant isolation, and what it describes is physical separation: tenants' rows sit in the same database and share its compute and storage. Logical isolation then depends on enforcement, since queries must never expose another tenant's data, and the guide names row-level security as one way to scope query results to a single tenant. Shared compute raises the risk of a noisy neighbor, where one busy tenant slows the others, and Azure has no built-in way to measure resource use by an individual tenant inside that database, so per-tenant monitoring has to come from the application. Restoring one tenant to an earlier point in time is complex in that model. With a database per tenant, isolation is high and one tenant can be restored without affecting the others, at the price of more databases to deploy schema changes to and monitor.
Separate schemas inside one database are a third option. In Azure SQL Database, backups and point-in-time restore work on the whole database, so a tenant in its own schema is backed up and restored along with every other tenant. The schemas share the same compute, so the noisy-neighbor risk stays. A single application login that can read every schema is not a boundary between them. Schema-level permissions become one when each tenant's requests run under a database principal limited to that schema; row-level security driven by a trusted tenant value in session context is another way to enforce the boundary. Without either, separate schemas mainly add objects to migrate.
A shared database with enforced tenant scoping can suit an application whose tenants have no separate restore, retention, residency or performance requirement. A separate database earns its cost when a tenant needs one of those. Microsoft's hybrid pattern lets a tenant move from a shared database to its own later, and it relies on every database carrying the tenant identifier in its schema.
What support needs on screen
When a user reports that a work order disappeared, support should be able to see the active tenant, the user's roles, the record's tenant, recent tenant switches and the last import status, and tell whether the record was hidden by permissions, archived by a rule or never created. When an integration fails, the failed-sync queue should show the tenant, the external system, credential status, retry count, last error and whether replay is safe.
Without that screen, support may resort to screenshots, ad hoc SQL against production or broad cross-tenant access. Those workarounds can expose records outside the intended scope. Emergency cross-tenant access should be recorded with the tenant, record, reason and timestamp.