Databricks row level security: the cache trap that slows and leaks data

Frank Shines

October 13, 2026

Databricks Row Level Security: Databricks row level security: the cache trap that slows and leaks data

Databricks row level security filters rows per user, so one cached answer can no longer serve everyone. Turn it on carelessly and Power BI dashboards run many times slower. Add a cache that is not keyed to identity and one user’s rows reach another. Scope every cache to the user before you switch on any filter.

A cache that leaks rows between users is a data breach. IBM’s 2026 Cost of a Data Breach Report puts the global average cost of one at a record $4.99 million. Here is how one lakehouse build got close.

The gold layer was fast and the Power BI dashboards loaded quickly. Then the team switched on per-user row filters, and the same dashboards ran many times slower.

The fix that followed was worse. A cache added to win back speed served one user’s result to another user. That’s a data exposure, not a performance bug.

I’ve spent 30+ years implementing enterprise systems at IBM, Ernst & Young, Johnson & Johnson and McKesson. As a Lean Six Sigma Master Black Belt, I learned one thing early: fix the process order before you add the control. Secure. Solve. Scale. is that order here. Secure the cache by keying it to identity, solve the speed problem the filters create, then scale the filters out to every user.

How does RLS work in Unity Catalog and in Power BI?

In a Databricks lakehouse, Auto Loader lands raw files in bronze, silver cleans them, and gold serves the views Power BI reads. A Unity Catalog row filter is a SQL function attached to a table. Every query against that table runs the function and returns only the rows the caller is allowed to see.

The function usually checks current_user() or is_account_group_member(). A column mask works the same way. Instead of dropping rows, it rewrites a column’s value for callers who shouldn’t see it.

For Power BI RLS on Databricks, Power BI connects via DirectQuery with Entra ID SSO. The SQL warehouse runs each query as the viewer, so a regional manager sees only their region. Lakehouse access control then lives once, in Unity Catalog, not in every semantic model.

Power BI also has its own RLS roles, defined inside the semantic model. They are the right tool for import models. They are also a second set of rules you have to keep in sync.

Why does dynamic row-level security (RLS) defeat result caching?

A result cache works because identical SQL returns an identical answer. Run a heavy aggregation once, and the next person with the same query gets the stored result almost instantly. No new compute spins up.

Dynamic row-level security (RLS) breaks that promise. The SQL text stays the same, but the answer now depends on who asks. A shared cache can’t reuse it safely.

On the build I described, every page load and cross-filter became a live warehouse query. Concurrency climbed, queries queued, and the dashboards ran many times slower. Nothing was broken. The cache simply had nothing it could share.

What breaks when row filters meet a shared cache?

Three problems arrive together, and most teams only see the first one.

Serverless compute bills climb

Every query the cache can no longer answer runs live on the SQL warehouse. On a serverless warehouse, that shows up as more clusters scaling out and more billed compute for the same dashboards. Databricks SQL serverless performance looks fine in testing, then costs far more at peak, because the test ran against a warm cache.

AI agents read whatever the cache hands them

Gold-layer results no longer feed only dashboards. An LLM assistant or AI agent that queries the lakehouse through a middleware cache can pull a result built for someone else. Then the leaked rows don’t sit on one screen. They land in a prompt, a summary or a log. Data leak prevention for LLMs starts with the same rule: every request carries the real caller’s identity, and every cache keys on it.

Two rule sets drift apart

Teams that keep rules in Unity Catalog and again as Power BI RLS roles maintain two copies of one policy. Someone changes a region mapping in one place and not the other. Nobody notices until an auditor or a regional manager does. That governance drift grows with every semantic model you add.

What is the identity-scoped cache rule?

The rule is short: never switch on row-level security before the cache is identity-scoped. Break it and you trade a speed problem for a leak.

Under pressure to get speed back, teams add a cache in the BI layer or a middleware service. If that cache keys on the query alone, it hands the first caller’s result to everyone who follows. The Unity Catalog row filter ran once, for the wrong person.

An identity-scoped cache keys on the query and the caller’s identity together. For group-based filters, the user’s group set is a safe key. For per-user filters, nothing short of the user ID is safe. It’s Zero Trust data architecture applied at the cache: no stored result is trusted for a caller until the key proves who asked. Our guide to attribute-based access control in Unity Catalog shows how tags and policies decide what each identity sees.

Why can a “missing report” be another user’s cached result?

Here is the failure from that build. A manager opened a Power BI report and saw what looked like a missing report: empty visuals, nothing to drill into. The report was fine.

Another user had run the same report first. The cache stored that result without the user’s identity in the key, then served it to the manager. This time the mismatch showed up as blanks.

Don’t count on blanks next time. On a different report, the same flaw puts User A’s protected rows on User B’s screen. Treat any “missing report” ticket after an RLS change as a possible cache leak until you prove otherwise.

Which patterns fit group-based filters, row filters and column masks?

Each pattern runs in a different place and puts a different demand on the cache. Pick the wrong one and you pay in compute or in exposure. The table below shows what each cache must key on.

Pattern Where it runs Best fit What the cache must key on
Group-based row filter Unity Catalog row filter calling is_account_group_member() Department or region isolation The user’s group set. Results are reusable for everyone in the same groups.
Dynamic per-user row filter Unity Catalog row filter calling current_user() Strict per-person or multi-tenant isolation The user ID. No result is reusable across users.
Dynamic column masking Unity Catalog column mask function Redacting PII while keeping row counts The same identity or groups the mask checks.
Power BI RLS roles Power BI semantic model Import models refreshed by one identity Power BI applies roles per viewer. The rules live outside Unity Catalog.

 

Keep the rules in the catalog wherever you can. Split them between Unity Catalog and Power BI and you get two sources of truth that drift apart. Databricks dynamic column masking and row filters belong in the same policy layer, reviewed together.

Masks change caching too. A mask that shows full Social Security numbers to HR and redacted ones to everyone else returns different values per group. Key the cache on the same groups the mask checks, and the redaction holds for every BI tool and AI agent downstream.

How do you test row-level security before go-live?

Run three passes in order. Each one catches a failure the others miss.

Prove identity reaches the warehouse

  1. Check single sign-on: Confirm the Power BI connection uses DirectQuery with Entra ID SSO, not a shared credential.
  2. Read the query history: Each test query should show the viewer’s identity, not a service principal.
  3. Review the filter function: Confirm it calls current_user() or is_account_group_member() against groups that actually exist.

Load-test with caching out of the picture

  1. Read the query profile: If the filter joins a mapping table, that small table should broadcast. A shuffle on every query means the filter is doing too much work.
  2. Simulate peak concurrency: Run your busiest hour of dashboard traffic with per-user filters on.
  3. Size the warehouse: Set serverless SQL warehouse scaling for the live-query load, not the cached load you had before.

Try to leak data on purpose

  1. Run the report twice: Open the same report as two users with different access, back to back.
  2. Compare row by row: Any protected row that appears in both result sets is a failure.
  3. Repeat at every cache layer: Test the BI cache, any middleware, any API cache and any cache in front of an AI agent separately.

Which row-level security pattern should your lakehouse switch on first?

Start with granularity. If a department or region boundary covers the need, switch on group-based filters and key the cache on groups. Results stay reusable within each group, so most of your caching survives. Reach for dynamic per-user filters only when the business requires them, and budget serverless capacity for live queries when you do.

Then commit to the order: identity-scoped cache first, row filters second, go-live third. Skip a step and you trade a speed problem for a leak. That sequence is what Analytics AIML brings to Databricks data engineering work. It’s first-principles thinking applied to lakehouse access control.

If you’re about to switch on row filters under Power BI, talk to Analytics AIML about our AI governance and compliance services. We’ll check the cache order before your users find the gap.

Frequently Asked Questions (FAQs)

Does Power BI import mode respect Unity Catalog row filters?

Not for report viewers. In import mode, the row filter runs once, for the identity that refreshes the model. Every viewer then sees that identity’s rows unless you rebuild the rules as Power BI RLS roles.

Should row-level security live in Unity Catalog or in Power BI?

Put it in Unity Catalog when Power BI runs in DirectQuery with single sign-on. One set of rules then covers Power BI, notebooks, SQL and every other tool on the lakehouse. Use Power BI roles only for import models.

How do you optimize Databricks SQL serverless caching with row-level security?

Key every cache on the query text, its parameters and the identity the filter checks: the user ID for per-user filters, the full group set for group-based filters. Prefer group-based filters where the business allows, so results stay reusable. Then size serverless warehouse scaling for the live-query load, not the cached one.

How can AI governance prevent data leaks in Databricks and Power BI?

Treat access policy as one governed asset. Keep row filters and column masks in Unity Catalog, make every BI tool, API and AI agent query as the real caller, and test each cache layer for cross-user leaks before go-live. Review the query history after every rule change.

How do you tell a real missing report from a cache leak?

Run the report as the affected user with caching off. If the data appears, the cache served someone else’s result. Then check the query history to see which identity actually ran the original query.

Analytics AIML is an AI performance firm. We rebuild the three foundations that decide whether an AI investment ships, scales, and shows up on the P&L: a sharper problem, a governed data foundation, and demand that survives the zero-click age.

— Rise above the flood

Build a content engine that gets cited.

AIMGrowth is the discipline for the AI-answer economy. We ship it in 90 days, fixed scope.