100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Row-Level Security

How Power BI restricts which data rows a user can see through DAX-defined roles, the static-vs-dynamic distinction, and what RLS does not protect.

Service & SharingAdvanced10 min readJul 10, 2026
Analogies

Row-Level Security

Row-level security (RLS) restricts which rows of data a user can see within a shared dataset by defining roles in Power BI Desktop, each with a DAX filter expression applied to one or more tables — for example, [Region] = USERPRINCIPALNAME() on a Sales table restricts a salesperson to only rows matching their signed-in email. These filters are enforced at query time inside the dataset's storage engine, so every visual, every drill-through, and every export automatically respects the restriction regardless of which report a user opens.

🏏

Cricket analogy: RLS is like a stadium's ticketing system that only lets a season-ticket holder's turnstile scan grant access to their own stand's seating section, regardless of which entrance gate they walk through.

Static vs Dynamic RLS and Testing Roles

Static RLS hardcodes filter values per role (for example, a 'West Region' role filtered to [Region] = "West"), requiring a new role for every distinct value, while dynamic RLS uses functions like USERPRINCIPALNAME() or LOOKUPVALUE() against a mapping table so one role scales to every user automatically. Before publishing, authors validate roles using Desktop's 'View As' feature, which temporarily impersonates a role (or a specific user's email under dynamic RLS) to confirm the correct rows are visible without needing to actually sign in as that user.

🏏

Cricket analogy: Static RLS is like printing a separate physical pass for each stand of the stadium, while dynamic RLS is like a single smart wristband that automatically opens the gate matching whichever seat is registered to that fan's ticket ID.

dax
// Dynamic RLS filter expression applied to the Sales table
'Sales'[Region] =
LOOKUPVALUE (
    'RegionManagerMap'[Region],
    'RegionManagerMap'[ManagerEmail], USERPRINCIPALNAME()
)

Use Desktop's Modeling > Manage Roles to define roles, then View As to impersonate a role — or a specific email under dynamic RLS — before publishing, so you catch a wrong LOOKUPVALUE join or missing mapping row before real users do.

Limitations: What RLS Does Not Protect

RLS only takes effect once a report is viewed through the Power BI Service (or embedded with an effective identity) — anyone with edit access to the underlying .pbix file in Desktop, or workspace Admin/Member/Contributor roles with build permission, can bypass it entirely and see unfiltered data. RLS also filters existing rows rather than aggregated totals computed before filtering, so measures using functions like ALL() or REMOVEFILTERS() can inadvertently leak totals across restricted rows if not written carefully to respect the active role filter.

🏏

Cricket analogy: It's like a stadium's ticket-gate restriction only applying to spectators entering through the public turnstiles — ground staff with a master keycard can walk into any stand regardless, and a poorly designed scoreboard formula could still show the combined total from every stand.

RLS enforced in the Service does not protect the .pbix file itself — anyone with edit rights to the file in Desktop, or a workspace role with Build permission, can see completely unfiltered data. Never treat RLS as a substitute for controlling who has edit access to the underlying content.

  • RLS restricts visible rows per user by applying a DAX filter expression through roles defined in Desktop.
  • Static RLS hardcodes filter values per role; dynamic RLS uses USERPRINCIPALNAME()/LOOKUPVALUE() to scale to any user.
  • RLS is enforced at query time in the dataset's storage engine, covering every visual, drill-through, and export.
  • Use Desktop's 'View As' feature to test roles (or specific dynamic users) before publishing.
  • RLS only applies when content is viewed through the Service or embedded with an effective identity.
  • Anyone with .pbix edit access or workspace Build/Contributor/Member/Admin rights can bypass RLS entirely.
  • Measures using ALL() or REMOVEFILTERS() must be written carefully or they can leak totals across restricted rows.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#PowerBIStudyNotes#RowLevelSecurity#Row#Level#Security#Static#StudyNotes#SkillVeris#ExamPrep