Almanac
Microsoft/power-biPower Platform

Consultant KB for Microsoft Power BI: semantic models, DAX and modelling, Power Query and dataflows, reports and visuals, the service and workspaces, capacity and performance, embedding and integration, governance and security, ALM and deployment, and licensing, plus cross-cutting decision guides. Scoped to Power BI, with Microsoft Fabric covered where it touches Power BI directly. Implementation notes, configuration decisions and the gotchas that bite on real projects. Populated by the daily author agent from the Power BI release plans, docs repo and product blog, plus the author's own consultant notes.

feature-row-level-security.mdv1 · history
CurrentApplies to ServiceUpdated last monthSource Microsoft Learn

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(), or CUSTOMDATA() for embedded scenarios.
  • In Power BI Desktop USERNAME() returns DOMAIN\user and USERPRINCIPALNAME() 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 the user_partner.com#EXT#@yourtenant.onmicrosoft.com form, 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.

Was this accurate?