Row-Level Security in Power BI Over Dynamics Data Without Premium Capacity
A technical guide for a multi-country manager rollout on Pro licences: a security table keyed on user principal name, the USERPRINCIPALNAME() rule, testing with View as, mapping drift, the Dynamics manager hierarchy, live connections and the note legal will ask for.
Row-level security in Power BI works without Premium capacity: it is part of the semantic model, so Pro licensing is enough, provided every viewer has a Pro or equivalent licence. It is not a switch, though. You need a mapping table that says which user sees which territories or teams, and a model designed around it. Build a security table keyed on user principal name, relate it to the dimension that filters your facts, add a role whose DAX filter compares that table with USERPRINCIPALNAME(), and test with View as before publishing. For fifty managers across countries, plan for mapping drift, the manager hierarchy, live connection behaviour and a written note for legal.
Does Power BI row-level security really work without Premium capacity?
Yes. Row-level security is defined in the semantic model and enforced by the Power BI service whether the workspace sits on shared capacity or on Premium or Fabric capacity. What Premium changes is who may view content, not whether RLS applies: on shared capacity, every person who opens the report needs a Power BI Pro licence, or Premium Per User if the workspace uses that. Licence names, capacity tiers and what each includes change, so check current Microsoft documentation before you commit a rollout plan to a licence assumption.
The honest constraint is design, not licensing. RLS filters rows by rules you write, and those rules need data to work from: a table that maps each person to what they may see. If that table does not exist, or the model has country and team names scattered across flat fact tables, there is nothing clean for a rule to filter. Our Power BI for manufacturing guide makes the same point about setting RLS early and explains the star schema and Dataverse connection choices underneath; this page covers only the security layer on top.
Who does row-level security not apply to?
This is the first thing legal will ask, and the answer surprises people. RLS applies to users who consume content: people with the Viewer role in the workspace, people the report or app is shared with, and people with Build permission on the semantic model. It does not apply to workspace Admins, Members or Contributors, who can see all rows. The model author in Power BI Desktop also sees everything unless they deliberately test as a role.
So the separation you promise is only as good as your workspace membership. Keep managers out of editing roles, give them access through a Power BI app or the Viewer role, and keep the list of people with Admin, Member or Contributor access short, named and reviewed.
How do you build a security table keyed on user principal name?
Make one table with one row per person per thing they may see. For a territory model that is two columns: UserPrincipalName and TerritoryKey. A manager covering three territories has three rows. A regional director can have a row per territory in the region, or a flag that grants all rows, handled in the rule.
Source it from Dynamics 365 rather than a spreadsheet wherever possible. The systemuser table carries the sign-in name in the domainname column, and territory, business unit and team membership already live in Dataverse, so a query over those tables keeps the mapping in step with the system people actually maintain. Normalise the name to lower case on both sides. Do not use the email address column as a stand-in for the user principal name; they often differ, especially after mergers or renames.
- Keep the security table small and separate from facts: people and keys only, no measures.
- Connect it, by a relationship or a DAX filter, to a dimension such as Territory, Business Unit or User, never directly to a fact table with many rows per key.
- Hide the table from report view so it does not appear in the field list.
- Decide what happens for a person with no rows: the safe default is that they see nothing, and you monitor for it.
How do you write the USERPRINCIPALNAME() filter and connect it to the facts?
There are two common shapes. Pick one and use it consistently.
The first puts the rule on the security table itself, with a filter such as LOWER('Security'[UserPrincipalName]) = LOWER(USERPRINCIPALNAME()), and relies on the relationship from the security table to the Territory dimension to carry the filter to the facts. Because the security table is on the many side, that relationship has to filter in both directions and have "Apply security filter in both directions" enabled. It works, but bidirectional relationships can create ambiguity and slower queries as the model grows.
The second puts the rule on the dimension and leaves the security table unrelated: on Territory, a filter such as 'Territory'[TerritoryKey] IN CALCULATETABLE(VALUES('Security'[TerritoryKey]), 'Security'[UserPrincipalName] = LOWER(USERPRINCIPALNAME())). The Territory dimension then filters the facts through ordinary single-direction relationships. For most Dynamics models with one or two security dimensions we prefer this shape, because it keeps the relationship layout simple.
Create one role, not a role per country. Assign a Microsoft Entra security group containing all managers to that role in the service, and let the table decide what each person sees. Fifty static roles are fifty places to make a mistake.
How do you test row-level security with View as before managers see it?
Test in both places, with named sample users, and keep the evidence.
- In Power BI Desktop, use Modeling, View as, select the role and Other user, and enter a real user principal name. Check totals, not just that the page renders.
- After publishing, open the semantic model's Security settings, choose Test as role, and test the same users again against the service.
- Pick test users deliberately: a manager with one territory, one with several, a regional director, a person who moved territory recently, a guest user if you have any, and a person with no mapping who should see nothing.
- Compare each result with a count taken straight from Dynamics 365 for the same scope, so the check is independent of the model.
- Screenshot or export each result with the date, the user tested and the model version, because this becomes part of the note for legal.
- Finally, ask one real manager to open the published app while you watch, since your own account may be a workspace member that bypasses RLS.
What is mapping drift, and how do you stop it breaking access after go-live?
Mapping drift is the security table slowly disagreeing with reality: a manager changes country, a territory is split, someone joins, someone leaves, a user principal name changes after a rename. RLS keeps enforcing the old answer, so people see too much or too little and nobody notices until they complain or an auditor tests it.
- Build the mapping from Dataverse at refresh time rather than from a hand-edited file, so a change in Dynamics flows through on the next refresh.
- Remember the lag: on shared capacity, scheduled refreshes are limited per day, so a reorganisation takes effect at the next refresh, not instantly. Check current documentation for the limit that applies to you.
- Add a small exceptions report for administrators: active users in the managers group with no mapping rows, mapping rows for disabled users, and users mapped to territories that no longer exist.
- Give the mapping a business owner, usually sales operations or HR, and review it on every reorganisation and at least quarterly.
- Remove leavers from the Entra group as part of the leaver process, so a stale row alone never grants access.
How do you let managers see their own team through the Dynamics manager hierarchy?
When the rule is "a manager sees records owned by anyone who reports to them, at any depth", a flat territory table is not enough. Dynamics 365 already holds the hierarchy: each systemuser row has a manager in parentsystemuserid. Bring the users into a User dimension with their id, manager id and user principal name, and add a calculated column with PATH('User'[UserId], 'User'[ManagerId]), which produces the chain of ids from the top of the hierarchy down to each person.
The role filter on the User dimension is then PATHCONTAINS('User'[HierarchyPath], LOOKUPVALUE('User'[UserId], 'User'[UserPrincipalName], LOWER(USERPRINCIPALNAME()))). A manager sees themselves and everyone below them, and the User dimension filters facts by owner. Two cautions. The hierarchy in Dynamics is only as accurate as the manager field, which is often neglected, so check it before trusting it. And ownership by teams or queues rather than users needs an extra rule, because those records have no person in the chain. How business units, teams and hierarchy security behave inside Dynamics itself is covered in our guide to Dynamics 365 business units and teams.
What breaks when the report uses a live Dataverse connection instead of import?
With import, the model holds a copy of the data read by the refresh account, so Dynamics 365 security roles play no part and RLS is the only barrier. That is simple to reason about, and it is why the mapping and testing above matter so much.
With DirectQuery to Dataverse, queries run live, and the behaviour changes. Where single sign-on is enabled for the data source, queries run as the viewing user, so Dynamics 365 security roles filter rows as well as your RLS rule. The two layers can disagree, and the user sees the intersection, which is hard to explain when a number looks wrong. Each viewer then also needs access to Dataverse itself. Calculated columns such as the PATH hierarchy column are limited in DirectQuery, row limits and query timeouts apply to the Dataverse endpoint, and every RLS filter is pushed into every live query, so heavy rules slow pages down. The choice of connection mode by data volume is in the Power BI for manufacturing guide. DirectQuery and single sign-on options for Dataverse change, so check current Microsoft documentation. For a fifty-manager rollout in a week, an imported model with one well-tested RLS rule is usually the safer choice.
What should you write down for legal about data separation?
Write a short, plain note that someone outside IT can check against the system. It is not legal advice, and your legal team decides what is sufficient, but these are the facts they will need.
| Topic | What to record |
|---|---|
| What is separated | Which tables and reports are filtered, and by what: territory, business unit, team or manager hierarchy |
| How it is enforced | The single role, its DAX rule in words, and that it is applied by the Power BI service to viewers |
| Who is not filtered | Named workspace Admins, Members and Contributors, and anyone able to edit or download the model |
| Where the mapping comes from | The Dynamics 365 tables, the refresh schedule and the delay between a change in Dynamics and a change in access |
| What it is not | RLS is a filter on one shared model, not physical separation; the data for all countries sits in the same semantic model in the same tenant |
| Evidence | Dated test results per sample user, the model version, and the exceptions report reviewed on a schedule |
| Exports and sharing | Tenant and workspace settings for export, Analyze in Excel, sharing and Build permission, and who approved them |
When is row-level security not the right answer for multi-country data?
When legal requires physical separation, data residency per country, or a guarantee that no administrator in one country can see another country's rows. RLS cannot give that, because the model holds all the data and editors bypass the filter. The options then are separate semantic models and workspaces per country, each loaded only with that country's rows and administered by that country, at the cost of more models to maintain.
The same question can reach the CRM itself. We recommend the right solution - whether that's Microsoft Dynamics 365, Power Platform, or a custom-built CRM. Some businesses need the Microsoft ecosystem. Others need full control without licensing. We deliver both. Where regulation or licensing makes a shared Microsoft tenant a poor fit, a custom-built CRM on React, Node.js, PostgreSQL or .NET can hold each country's data in its own database with reporting built in, without per-user Microsoft licensing.
Should reporting over sensitive multi-country data stay on Microsoft or move to a custom build?
Can afford licensing and want the Microsoft ecosystem
Dynamics 365
Microsoft 365, Teams and Outlook integration, a mature partner ecosystem, Copilot, and apps for sales, service and field operations that are configured rather than built.
Need full control and zero licensing
Custom CRM
A CRM built on React, Node.js, PostgreSQL or .NET that you own outright: your data model, your hosting, no per-user subscription, and features shaped exactly to your process.
Not sure which fits
We help you decide
A short discovery weighs licensing budget, process complexity, integrations and long-term ownership, then recommends one path. We deliver both, so the recommendation has no reason to lean.
How does Solzet set up row-level security for a multi-country Dynamics rollout?
As a short configuration engagement with a fixed outcome. We read the existing model and the Dynamics 365 security setup, agree the rule with the business and legal in one sentence, build the security table from Dataverse, restructure the model where the rule has nothing clean to filter, implement one role assigned to an Entra group, test named sample users against independent counts, and hand over the exceptions report and the note for legal. Your team keeps running it.
The work is done by senior consultants and full-stack developers delivering remotely from Yerevan, Armenia, with 8+ years of Dynamics 365 Customer Engagement and Power Platform work, directly for your team or white-label for Microsoft partners. If the reports then need to appear inside Dynamics 365 forms and dashboards, our Power BI embedding troubleshooting guide covers why embeds fail for viewing users, and a wider review of security and data quality is part of our Dynamics 365 health check.
What do people ask us?
Can I use row-level security in Power BI without Premium?
Yes. Row-level security is defined in the semantic model and enforced by the Power BI service on shared capacity as well as Premium or Fabric capacity. Without Premium, every viewer needs a Pro licence, or Premium Per User where the workspace uses it. Licensing changes, so check current Microsoft documentation before planning a rollout.
How do I make each manager see only their own team in Power BI over Dynamics 365?
Build a security table keyed on user principal name and sourced from Dynamics 365, relate or filter it to the Territory, Business Unit or User dimension, and create one role whose DAX rule compares it with USERPRINCIPALNAME(). For "everyone who reports to me", use the Dynamics manager field with PATH and PATHCONTAINS on a User dimension.
Why can some users still see all the data despite row-level security?
Row-level security only applies to viewers. Workspace Admins, Members and Contributors see all rows, and so does anyone testing in Power BI Desktop without choosing a role. Give managers access through an app or the Viewer role, and keep editing roles to a short named list.
How do I test Power BI row-level security for a specific user?
In Power BI Desktop use View as with the role and Other user, entering the person's user principal name. After publishing, use Test as role in the semantic model's security settings. Test a manager with one territory, one with several, a recent mover and an unmapped user, and compare each result with counts from Dynamics 365.
Does Dynamics 365 security carry through to Power BI automatically?
Not with import mode: the model holds data read by the refresh account, so row-level security is the only filter. With DirectQuery and single sign-on to Dataverse, queries run as the viewing user and Dynamics 365 security roles apply as well as RLS. Check current Microsoft documentation for the options available to your environment.
What is the best way to keep the RLS mapping table up to date?
Build it from Dataverse tables at every refresh instead of a hand-edited file, give it a business owner, and run an exceptions report listing unmapped managers, rows for disabled users and territories that no longer exist. Remember that access changes only at the next scheduled refresh, so tell the business about that delay.
Is row-level security enough for legal data separation between countries?
Sometimes. RLS filters one shared model, and editors bypass it, so it is not physical separation or data residency. Record what is filtered, who is exempt, where the mapping comes from and the test evidence, and let legal decide. Where physical separation is required, use separate models and workspaces per country.
Where should you go next?
Embedding Power BI in Dynamics 365 when it fails
The settings, permissions and diagnostic order for reports that will not load inside Dynamics 365.
Power BI for manufacturing
Star schema, date tables and choosing the Dataverse connection mode under your reports.
Dynamics 365 business units and teams
How access to records is structured inside Dynamics 365 itself.
Dynamics 365 health check
An independent review of security, data quality, performance and governance.
Power Platform consulting
Senior developers for Power BI over Dataverse, Power Apps, Power Automate and Power Pages.
Custom CRM Development
CRM on React, Node.js, PostgreSQL and .NET for organizations that need full control without Microsoft licensing.
Which solution is right for your business?
Tell us what you need. A senior consultant replies within one business day with a recommendation - Dynamics 365, Power Platform, or a custom-built CRM - not a sales script.