Teams, Business Units & Scalable Access in Dataverse: A Step-by-Step Walkthrough (Part 2)

In Part 1 we set up row-level and column-level security for a single user — Jordan, an HR employee at Contoso. The mechanics worked, but the setup had a built-in scaling problem: every new user needs to be manually added to the right Security Role and Column Security Profile. In a real organisation, that becomes an admin burden fast.

This post fixes that. The approach is to stop assigning access to individuals and start assigning it to Teams. A user joins the right team, and the correct access follows automatically — no per-user configuration needed.

Along the way, this post also covers Business Units for organisational boundaries and Member’s Privilege Inheritance in full with a live demonstration using team-owned records.


Where We Left Off

At the end of Part 1, the Contoso environment had:

  • An Employee Salary table with rows owned by Alex and Jordan
  • An Employee Self-Service Security Role with User-level Read, assigned directly to Jordan
  • An HR Salary Access Column Security Profile covering the Salary column, with Jordan assigned directly as a user
  • Basic User assigned to Jordan

Jordan can see their own row and the Salary column. No one else can. But the remaining people in our cast — Morgan (Jordan’s HR manager) and Sam (Finance employee) — are not in the environment yet, and adding them as individuals would just repeat the same manual process.


The Plan

The shift we are making in this post:

  1. Create two Business UnitsContoso - HR and Contoso - Finance — so departments have a structural boundary in Dataverse
  2. Add Morgan and Sam as users, placed into the right Business Units
  3. Create an Owner Team for HR and assign the Employee Self-Service Security Role and HR Salary Access Column Security Profile to the team
  4. Move Jordan into that team, migrating their access from individual assignment to team membership
  5. Add Morgan to the same team and verify automatic access inheritance
  6. Demonstrate Member’s Privilege Inheritance fully — including assigning a record to the team entity and watching what each setting actually shows

Sam’s setup demonstrates the BU boundary — a Finance user with no HR team membership cannot see HR salary rows regardless of role.


Business Units

A Business Unit in Dataverse is an organisational container. Every user belongs to exactly one Business Unit, and the Business Unit access level on a Security Role determines whether that user can see records owned by people in other Business Units.

Contoso currently has only the root Business Unit, which every environment starts with. Alex and Jordan are both in it. That is fine for a single-department setup, but once Sam from Finance enters the picture, you want a boundary between HR and Finance data.

Contoso Business Unit hierarchyTree diagram showing root Contoso at top, with Contoso HR and Contoso Finance as child units. Alex in root, Jordan and Morgan in HR, Sam in Finance. HR Team shown as a dashed box under HR.Contoso (root)Alex · System AdministratorContoso – HRJordan · MorganContoso – FinanceSamHR Team (Owner Team)Jordan · Morgan (members)Dashed outline = Owner Team (created later in this post)

The parent-child relationship matters: users in a child Business Unit cannot see records owned by users in a sibling Business Unit unless their Security Role grants Business Unit or Organisation-level access. The root unit sits above both, so Alex retains visibility across everything.

Creating the Business Units

Alex goes to the Admin Center → your environment → SettingsUsers + permissionsBusiness units+ New.

Create two Business Units in this order:

  • Contoso - HR (parent: the root Contoso unit)
  • Contoso - Finance (parent: the root Contoso unit)

You’ll notice extra teams appear automatically. As soon as you create each Business Unit, Dataverse creates a matching default Owner Team with the same name. This is not unique to the BUs you just created — the root Business Unit has always had one too, and every user who has not been moved elsewhere (Alex included) has been a member of it since the environment was provisioned. These default teams are system-managed: every user you assign to a Business Unit is automatically added to that BU’s default team, and you cannot add or remove members manually. Move a user to a different BU and Dataverse moves them to the new default team automatically. These default teams have no Security Roles or Column Security Profiles assigned out of the box, so they do not affect anything in this walkthrough. The HR Team created later in this post is a separate, manually managed Owner Team — that is the one driving access. If you open Teams in the Admin Center now, you can safely ignore the Contoso - HR, Contoso - Finance, and root entries you see there.

Three Things Named “Business Unit” — Worth Untangling Now

Before going further, it’s worth pausing on something that trips up almost everyone the first time they configure Dataverse security: the phrase “Business Unit” shows up in three different places across this walkthrough, and they are not the same setting.

Where it appearsWhat it actually controls
Business Unit field on a Security Role (set when you create the role)Which Business Unit the role record is filed under, for organisation and governance of your role library. In current Dataverse this is not an assignment restriction — a role can be assigned to a user or team from any Business Unit, regardless of which Business Unit they belong to (see Create or edit business units). It does not gate who can hold the role, and it does not control what data the role grants — that comes from the privilege access levels in the row below. Part 3 demonstrates this with a live test.
Business Unit access level on a table privilege (Read, Write, etc. inside a role — e.g. setting Employee Salary Read to Business Unit)How far that privilege reaches into the org chart at the moment it’s evaluated. It is checked against the Business Unit the assigned user or team belongs to right now — not against the role’s own home Business Unit field above. These two never have to match, and conflating them is one of the most common Dataverse security mix-ups.
Business Unit field on an Owner Team (you’ll set this when creating HR Team shortly)Which Business Unit a record belongs to when the team itself owns it. Functions the same way a user’s own Business Unit does for ownership purposes — see “Owner Teams are tied to a Business Unit” in Things Worth Knowing.

The middle row is the one to carry through the rest of this post: when a role privilege says “Business Unit,” it means the holder’s own Business Unit at evaluation time — full stop. It has nothing to do with which Business Unit a particular role record happens to be filed under.


Adding Users

Morgan and Sam need to exist as licensed users in the Microsoft 365 tenant before they can be added to the Dataverse environment. Once they do, Alex adds them in the Admin Center.

Go to Users + permissionsUsers+ Add users → search for each person by name or email → add them.

After adding them, assign each to the right Business Unit:

  • Open Morgan’s user record → Business Unit → change to Contoso - HR
  • Open Sam’s user record → Business Unit → change to Contoso - Finance

Jordan should also be moved to Contoso - HR at this point. Open Jordan’s user record and update the Business Unit field the same way.

Changing a user’s Business Unit reassigns their owned records to the new unit as well, and removes their directly assigned Security Roles. Both behaviors are configurable but on by default — see Create or edit business units for the underlying AlwaysMoveRecordToOwnerBusinessUnit and DoNotRemoveRolesOnChangeBusinessUnit settings if you need to change them. In a production environment with existing data, move users before they start creating records, and re-check their Security Roles immediately after the move — don’t assume they carried over. This walkthrough sequences Morgan’s and Sam’s BU moves before any custom role is assigned, specifically to avoid this trap.

Morgan and Sam each need the Basic User role to access the environment. Assign it to each of them via Manage security roles on their user records. Do not assign any custom roles yet — those will flow through team membership or be added later in this post.

While you have Morgan’s user record open, also set the Manager field to Alex as a placeholder for now. Part 3 uses this field when configuring hierarchical security.


Owner Teams

Dataverse has two kinds of teams: Owner Teams and Access Teams. This post covers Owner Teams, which is what you want for role-based access management. Access Teams — which are lighter-weight, record-scoped, and have no security roles — are covered in Part 4.

An Owner Team can be assigned Security Roles and Column Security Profiles, and every member of the team inherits those assignments. When someone joins the team, they get the access. When they leave, it is revoked. No per-user configuration required.

Before and after: individual vs team-based access assignmentTwo side-by-side panels. Before panel shows Security Role and Column Profile each connected individually to Jordan, with a note that each new user requires the same steps. After panel shows both assigned once to HR Team, with Jordan and Morgan as members inheriting access.Before — individualSecurity RoleEmployee Self-ServiceColumn ProfileHR Salary AccessJordanRepeat both steps for everynew HR user addedAfter — team-basedSecurity RoleEmployee Self-ServiceColumn ProfileHR Salary AccessHR TeamJordanMorganNew HR users: add to team only.Access follows automatically.

Create the HR Team

Go to Users + permissionsTeams+ Create team.

FieldValue
Team nameHR Team
Business UnitContoso - HR
Team typeOwner
Team administratorAlex

Save.

Assign the Security Role to the Team

Open the HR Team record → Manage security roles → tick Employee Self-Service and Basic User → Save.

Every member of HR Team now automatically inherits the Employee Self-Service Security Role. Alex no longer needs to assign it individually to each HR user.

Assign the Column Security Profile to the Team

Go to SettingsUsers + permissionsColumn security profiles → open HR Salary AccessTeams tab → + Add teams → select HR Team → Save.

Any member of HR Team can now read and edit the Salary column. No individual profile assignment needed.

Move Jordan to the Team

Open the HR Team record → Members tab → + Add members → search for Jordan → Add.

Now remove Jordan’s individual assignments — they are no longer needed and leaving them in place creates confusion about where access is actually coming from:

  • Open Jordan’s user record → Manage security roles → untick Employee Self-Service if it’s still listed there. (The Business Unit move earlier in “Adding Users” may have already stripped this direct assignment automatically — either way, confirm it is gone before continuing.)
  • Open the HR Salary Access Column Security Profile → Users tab → remove Jordan

Jordan’s access now flows entirely through team membership. Open the environment as Jordan and verify: Salary column is still visible, only Jordan’s own row appears. Nothing should have changed from Jordan’s perspective.

Add Morgan to the Team

Open the HR Team record → Members tab → + Add members → search for Morgan → Add.

Open a browser window as Morgan. Because Morgan’s Security Role is Employee Self-Service with User-level Read, Morgan can only see rows they own — which is none yet.

Create a row as Morgan and verify:

  • Morgan can see their own row and the Salary value on it
  • Morgan cannot see Jordan’s row or Alex’s row

This confirms that team membership is correctly wiring up both the row-level and column-level access in one step.


Member’s Privilege Inheritance — Seeing It in Practice

In Part 1, when creating the Employee Self-Service role, there was a field called Member’s privilege inheritance left at its default: Direct User (Basic) access level and Team privileges. Now that the role is assigned to a team, this setting has a concrete, testable effect. The full picture only becomes clear once you have a record owned by the team itself — so this section walks through that step first.

One Concept First — Privileges Are Always Additive

Before touching the setting, it helps to separate two things that are easy to conflate: whether a team’s role applies to its members at all, and how the access level on that role is evaluated for a given member.

The first part is not affected by Member’s Privilege Inheritance and never turns off. A user’s effective privileges are always the union of their own direct roles plus the roles of every team they belong to — this is true regardless of which Member’s Privilege Inheritance setting any of those roles use. Jordan having Basic User and being a member of HR Team (which carries Employee Self-Service) means Jordan has both roles’ privileges, full stop. There is no scenario in this walkthrough where Jordan is a member of HR Team but somehow does not receive Employee Self-Service’s privileges — that part is automatic and always on.

What Member’s Privilege Inheritance actually controls is narrower: it decides, for that specific role, whether a member’s User-level access level is evaluated against records the member personally owns, against records the team owns, or — under the default — both.

What the Two Options Do

Direct User (Basic) access level and Team privileges — the default, and the one used throughout this series. A member’s access level on the privilege is evaluated twice: once as if they personally held the role (so User-level Read covers their own records), and once for the team (so User-level Read also covers anything the team itself owns). Both checks are active simultaneously. This is why, under this default setting, a member sees their own records and the team’s records — not one or the other.

Team Privileges Only — a stricter, narrower mode. The member’s personal evaluation is switched off entirely. Only the team-ownership check remains. A member set up this way can see records the team owns, but not records they personally own, unless some other role (direct or via a different team) grants that separately.

Member’s Privilege Inheritance: which records each mode makes visibleTable comparing Direct User mode and Team Privileges Only mode across three ownership scenarios, for the Employee Self-Service role specifically.Record owned by…Direct User (Basic) + TeamTeam Privileges OnlyJordan personally (a team member)✓ Visible✗ Not visibleHR Team (the team entity itself)✓ Visible✓ VisibleA BU colleague not in the team✗ Not visible (User scope)✗ Not visible

Notice the middle row in both columns: the HR-Team-owned record is visible under both settings. That is the detail that trips people up — Team Privileges Only is not “the setting that turns on team-record visibility,” because team-record visibility is already on under the default. What Team Privileges Only actually does is turn off the personal, individually-owned-record visibility that the default setting grants alongside it. It narrows, rather than widens, what a member can see.

Getting a Team-Owned Record — Two Ways

To see the difference hands-on you need at least one record owned by the HR Team entity rather than by a person. There are two ways to get one, and it is worth knowing both because real-world teams typically use the second.

Option A — create it as a person, then reassign it. This needs the Assign privilege in the Employee Self-Service role. Go to Security roles → open Employee Self-Service → find the Employee Salary table → set Assign to User → Save. (User scope means a member can only reassign records they personally own.) Log in as Jordan, open Jordan’s row, and on the command bar choose AssignAssign to team → select HR Team → OK.

Option B — create it owned by the team from the start. This is usually simpler and is how shared-queue scenarios work in practice: when creating a new Employee Salary row, the Owner field is just a lookup, and any owner-type record can have its Owner set directly to a team at creation time rather than defaulting to the creating user — provided whoever is creating it has Create privilege on the table. There is no separate “create as team” command; it is the same New Record form, with Owner pointed at HR Team instead of left on the default user.

Either path lands you in the same place: a row whose Owner is the HR Team entity. For this walkthrough, use Option A on Jordan’s existing row, since it also exercises the Assign privilege.

Once reassigned, refresh as Jordan. Jordan’s row is still visible — Jordan is a member of HR Team, and under the current Direct User (Basic) access level and Team privileges setting, team-owned records are already part of what Jordan can see. Nothing disappears yet. The Member’s Privilege Inheritance setting has not been changed at this point — only the record’s owner has.

Try It — Switch to Team Privileges Only

Go to Security roles → open Employee Self-Service → change Member’s privilege inheritance to Team Privileges Only → Save.

Open the table as Jordan. The HR-Team-owned row is still visible — team-record access was never lost. But Jordan’s other records, the ones still owned by Jordan personally (if any remain), disappear. Open as Morgan: Morgan can see the HR-Team-owned row, but no longer sees the personal row Morgan created earlier in this post.

Now create a new row as Morgan, owned by Morgan personally (the default). Refresh as Jordan. Jordan cannot see it — it belongs to Morgan individually, not to the HR Team, and under Team Privileges Only personal ownership no longer counts for this role.

This is exactly the behaviour Team Privileges Only is designed for. A real example: a shared HR case queue where every incoming case is created with Owner set to the HR Team directly (Option B above). Any team member can pick it up, work it, and resolve it — and, deliberately, none of them can see each other’s personal records through this role.

Switch Back to Direct User Mode

Go to Security roles → open Employee Self-Service → change Member’s privilege inheritance back to Direct User (Basic) access level and Team privileges → Save.

Jordan and Morgan can now see their own personally owned rows again, and the HR-Team-owned row continues to be visible throughout — it was never gated behind Team Privileges Only in the first place.

Leave the setting on Direct User (Basic) access level and Team privileges for the rest of this walkthrough. That is the correct setting for a self-service scenario where each person needs to see their own data, with team-owned records as a bonus rather than a replacement.


The Business Unit Boundary in Practice

Sam is in Contoso - Finance. Sam has Basic User but no custom Security Role and is not a member of HR Team. Log in as Sam and open the Employee Salary table. Sam sees no rows at all.

Alex creates the Finance equivalent of the HR role. Go to Security roles+ New role:

FieldValueNote
Role NameFinance Self-Service
Business UnitContoso - FinanceThis is the role’s home Business Unit — a filing/governance label, not an access level or an assignment restriction (see “Three Things Named Business Unit” above). It says nothing about which records the role can see; that comes from the access levels set below.
DescriptionAllows Finance employees to view and manage their own salary records
Applies ToUsers and Teams
Member’s privilege inheritanceDirect User (Basic) access level and Team privileges

Save. Now find the Employee Salary table and set the following privileges — mirroring the Create/Read/Write pattern Part 1 used for Employee Self-Service, since Sam needs to actually create and edit a row here, not just view one — leaving everything else at None:

PrivilegeAccess LevelWhy
CreateUserSam needs to create their own test row
ReadUserSam can only see rows they own
WriteUserSam can edit their own rows
DeleteNoneNot needed in this scenario
Append, Append To, Assign, ShareNoneNot needed in this scenario

Save and close.

Assign Finance Self-Service to Sam via Sam’s user record → Manage security roles.

Log in as Sam again. Sam can now create, see, and edit rows Sam creates, but still cannot see Jordan’s, Morgan’s, or the HR Team’s rows. The BU boundary holds regardless of what Security Role Sam has.


What the Access Structure Looks Like Now

UserBusiness UnitTeamSecurity Role sourceColumn Profile sourceCan see Salary?
AlexRootSystem Administrator (direct)Bypassed✓ Always
JordanContoso - HRHR TeamEmployee Self-Service (via team)HR Salary Access (via team)✓ Own row + team row
MorganContoso - HRHR TeamEmployee Self-Service (via team)HR Salary Access (via team)✓ Own row + team row
SamContoso - FinanceFinance Self-Service (direct)None✗ Blank

The key shift from Part 1: Jordan and Morgan’s core access is managed in one place — the HR Team. Adding a new HR employee is a single step: add them to the team. No per-user Security Role or Column Security Profile assignment needed.

Notice that Finance Self-Service is filed under Contoso - Finance while Employee Self-Service is filed under the root Business Unit — both work exactly as expected. As covered in “Three Things Named Business Unit,” the access check uses the privilege access level evaluated against the assigned user’s own BU, not the role’s home BU field. Part 3 demonstrates this with a live test.


Things Worth Knowing

Moving a user to a different Business Unit removes their directly assigned Security Roles by default. This is governed by the DoNotRemoveRolesOnChangeBusinessUnit setting (default false, meaning roles are removed) documented in Create or edit business units. A companion setting, AlwaysMoveRecordToOwnerBusinessUnit (default true), controls whether the user’s owned records move with them. Both are configurable, but assume the defaults unless you’ve checked otherwise. Always re-verify a user’s roles immediately after a BU change. Sequencing BU moves before role assignment, as this walkthrough does, sidesteps the issue entirely.

Every Business Unit — including root — gets a system-managed default team the moment it is created. These auto-created default Owner Teams have membership that is automatically synced to the BU’s users. You cannot manually edit their members, and they have no roles or profiles assigned out of the box. The root BU has always had one — Alex has been a member of it since the environment was provisioned. The HR Team you created manually is entirely separate and is the one carrying the Security Role and Column Security Profile.

A Security Role’s own Business Unit field is a governance label, not an access control. It does not restrict who can hold the role or what data the role grants. Current Dataverse explicitly allows a role to be assigned to a user or team from any Business Unit, regardless of which Business Unit they belong to (Create or edit business units). What actually controls which records a role’s holders can see is the access level (None / User / Business Unit / Parent:Child BU / Organisation) set on each privilege inside the role, evaluated against the assigned user’s own Business Unit at the moment access is checked. See “Three Things Named Business Unit” earlier in this post for the full breakdown.

Older Dataverse/CRM versions did restrict role assignment to a matching Business Unit by default. If your environment behaves that way, you are likely seeing legacy behaviour predating the “Record ownership across business units” feature — confirm directly rather than assuming either way.

Creating a new Business Unit does not duplicate, copy, or version existing Security Roles. Employee Self-Service stays a single role record throughout this entire series, filed under the root Business Unit from Part 1 onward — Dataverse does not create per-Business-Unit copies of it when Contoso - HR and Contoso - Finance are created. If you ever do see what looks like a duplicate-named role in your own environment, that’s almost certainly a deliberate copy someone made (via Copy security role), not something Dataverse generated automatically — check the Business Unit column to tell them apart.

Table ownership type is fixed at table creation and is what makes Business Unit-scoped access levels meaningful at all. Employee Salary is a User/Team-owned table — that choice, made when the table was created in Part 1, is a prerequisite for everything in this post. An Organisation-owned table only ever offers None or Organisation as access levels on its privileges; there is no per-record “owning Business Unit” to scope Business Unit or Parent:Child BU access against, because every record in an Organisation-owned table is implicitly visible to anyone with Organisation-level access and invisible to everyone else. This ownership type can’t be changed after a table is created, so it is worth a deliberate decision at design time rather than an afterthought.

The Assign privilege controls who can transfer record ownership — including to a team. Without it, the Assign button does not appear or is greyed out. The scope of Assign follows the same access level pattern as Read — User scope means you can only reassign records you personally own.

Team Privileges Only narrows access — it does not grant team-record visibility that the default setting lacked. Team-owned records are already visible to members under the default Direct User (Basic) access level and Team privileges setting; that part never changes. What Team Privileges Only does is switch off a member’s personal User-level visibility for that role, leaving only the team-ownership check. It is the right setting for shared queue patterns — a support inbox, an approvals queue, a shared caseload — where you deliberately want members to see only what the team owns and nothing they personally own through that role. For individual self-service where people should see their own data plus any team-owned records, keep the default.

Team membership changes propagate faster than Column Security Profile changes. If a user is added to a team but the Salary column is still blank, sign them out and back in. Role and profile changes from team membership can take a minute to take effect.

A user can belong to multiple teams. If Morgan also needs Finance data visibility for cross-department reporting, Morgan can be added to a Finance team without any conflict. The most permissive access level across all team memberships and direct assignments wins — Dataverse access is always additive.

Owner Teams are tied to a Business Unit. The HR Team was created under Contoso - HR. Members of this team inherit that Business Unit’s context for ownership purposes. A team can include users from other BUs, but the team’s home BU determines record ownership context.

Do not leave both direct and team-based assignments active for the same role. After migrating Jordan from direct assignment to team membership, the direct assignments were removed. Keeping both creates ambiguity about where access is coming from and makes future debugging harder.

A record can be created directly owned by a team — reassigning afterward is not the only path. The Owner field on any user/team-owned table is a normal lookup; if the person creating the record has Create privilege, they can set Owner to a team at creation time instead of leaving it on themselves. Shared-queue and case-management scenarios typically work this way from the start, rather than creating records as a person and reassigning them.

Basic User still needs to be assigned somewhere. It can be assigned directly to the user or added to the team’s security roles. Either works — just make sure every user has it, or they will hit an access error before any custom permissions are even evaluated.

Record sharing is the escape hatch for one-off exceptions. Everything in this post is about permanent, rule-based access. If you ever need to give Sam temporary visibility of one specific HR row — without touching roles, teams, or BUs — Dataverse’s Share feature handles that. The record owner shares it with Sam, choosing exactly which privileges Sam gets on that specific record. Sharing does not change ownership and can be revoked at any time. Part 4 covers sharing in full alongside Access Teams, which extend the same per-record sharing pattern to groups.

The Finance Self-Service role is assigned directly to Sam for now. A Finance team following the same pattern as HR Team is the natural next step — one team, one role assignment, all Finance users onboarded by adding them to the team. That pattern, along with Entra ID Group Teams that make team membership fully automatic, is what Part 4 covers.


What’s Next

Part 3 covers Security Role scoping in depth — the interplay between the role’s Business Unit field and the access levels on individual privileges — along with hierarchical security for manager visibility and the Parent:Child BU access level that lets Morgan see records in a child Business Unit under HR.

Comments