What it does
Filters rows out of a semantic model per user. You define roles with DAX filter expressions in Power BI Desktop, publish, then assign users or groups to those roles in the service. A filter returns TRUE or FALSE per row, and only TRUE rows survive — the rest are gone, not hidden.
Key facts
- RLS only applies to workspace Viewers. Admin, Member and Contributor all have edit permission on the model, so RLS doesn't apply to them. If you want RLS enforced on someone, Viewer is the only role you can give them.
- Viewers with Build permission are still filtered, including through Analyze in Excel.
- Static RLS hard-codes the value (
[Region] = "West"). Dynamic RLS resolves the signed-in user —USERPRINCIPALNAME(),USERNAME(), orCUSTOMDATA()for embedded scenarios. - In Power BI Desktop
USERNAME()returnsDOMAIN\userandUSERPRINCIPALNAME()returns a UPN. In the service both return the UPN. - Roles are additive. A user in both Sales and Marketing sees the union of both.
- Role membership accepts distribution groups, mail-enabled groups and Microsoft Entra security groups. Microsoft 365 groups aren't supported and can't be added.
- Only Import and DirectQuery are supported. For Analysis Services live connections you define security in the model, not in Power BI — the option doesn't appear.
- Service principals can't be added to an RLS role, so RLS isn't applied for apps where the service principal is the final effective identity.
- Role names can't contain a comma.
- Test as role doesn't work for DirectQuery models with SSO, doesn't work for paginated reports, and only shows reports from the semantic model's own workspace. It also doesn't cover Q&A, Quick insights or Copilot.
When to use / skip
Use it whenever more than one audience shares a model and shouldn't share the data — which in practice is most enterprise models. Prefer dynamic RLS with USERPRINCIPALNAME() and a mapping table over a wall of static roles; static roles look simpler on day one and become an administration problem by month three. Skip RLS and split the model instead when the security boundaries are coarse and permanent, when the filter logic starts needing bidirectional relationships to work, or when you genuinely need to hide columns rather than rows — that's object-level security's job.
Configuration decisions
- Static or dynamic, which really means: is the audience list stable and small, or does it change with the HR system?
- Where the user-to-data mapping table comes from, how it's refreshed, and what happens to a user with no matching row.
- Whether workspace roles are being used deliberately — giving a stakeholder Contributor "so they can have a look" silently disables RLS for them.
- Whether the model needs bidirectional security filtering, which you enable per relationship and which costs query performance.
- How external B2B guests are handled: direct email addresses on the role, or dynamic RLS keyed on whatever
USERPRINCIPALNAME()actually returns for them.
Gotchas
- This is where RLS silently doesn't apply: Contributor and above in the workspace, service principal embedding, and models with no RLS at all being reused by a new report. All three look fine and leak everything.
- A user assigned to no role typically sees nothing, because RLS is enforced but no role matches. Users report this as "the report is broken".
- For B2B guests
USERPRINCIPALNAME()might return[email protected]or theuser_partner.com#EXT#@yourtenant.onmicrosoft.comform, depending on tenant configuration. The format isn't guaranteed — put it in a card visual and have the guest look at it before you build the mapping. - Microsoft Entra security groups containing B2B guests may not resolve correctly for RLS. The documented workaround is to add external users to the role directly by email address.
- Test as role uses your identity for dynamic expressions, so it returns your UPN, not the simulated user's. It's useful for static roles and misleading for dynamic ones.
USERELATIONSHIP()can throw unexpected errors with RLS enabled. Microsoft's guidance is to redesign around it rather than work around it.- A report visual referencing a field the user can't see gives the same message as a deleted field. To the user, it reads as a broken report.
Consultant notes
- Write down the workspace role model at the same time as the RLS roles. Half of all RLS failures in the wild are a governance failure — someone got Contributor — rather than a DAX failure.
- Insist on testing with real accounts before go-live, especially for external users. Test as role is a development aid, not a UAT sign-off.
- If the client's answer to "who should see what" takes more than one workshop, that's the project. Budget for it as analysis rather than as configuration.
- Set expectations that RLS filters rows only. Users can still see every column, every measure and the full model schema for any row they're allowed. If that's a problem, you need OLS or separate models.
Worth revisiting if the B2B guest UPN resolution behaviour firms up, or if RLS starts applying to Contributors.