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, Member’s Privilege Inheritance in full with a live demonstration using team-owned records, hierarchical security so Morgan can access Jordan’s data as their manager, and the Parent:Child BU access level that governs visibility across a BU hierarchy.
Where We Left Off
At the end of Part 1, the Contoso environment had:
- An
Employee Salarytable with rows owned by Alex and Jordan - An
Employee Self-ServiceSecurity Role with User-level Read, assigned directly to Jordan - An
HR Salary AccessColumn 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. We also introduce Riley, an HR trainee, specifically to demonstrate the Parent:Child BU access level.
The Plan
The shift we are making in this post:
- Create three Business Units —
Contoso - HR,Contoso - HR Trainees(a child of HR), andContoso - Finance— so departments and sub-teams have a structural boundary in Dataverse - Add Morgan, Sam, and Riley as users, placed into the right Business Units
- Create an Owner Team for HR and assign the
Employee Self-ServiceSecurity Role andHR Salary AccessColumn Security Profile to the team - Move Jordan into that team, migrating their access from individual assignment to team membership
- Add Morgan to the same team and verify automatic access inheritance
- Demonstrate Member’s Privilege Inheritance fully — including assigning a record to the team entity and watching what each setting actually shows
- Set up hierarchical security so Morgan can see Jordan’s row as their manager
- Show how Parent:Child BU Read on Morgan’s manager role lets Morgan also see Riley’s row in the child BU
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.
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 → Settings → Users + permissions → Business units → + New.
Create three Business Units in this order:
Contoso - HR(parent: the root Contoso unit)Contoso - HR Trainees(parent:Contoso - HR)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 Teamcreated 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 theContoso - HR,Contoso - HR Trainees,Contoso - Finance, and root entries you see there.
Adding Users
Morgan, Sam, and Riley 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 + permissions → Users → + 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 - Open Riley’s user record → Business Unit → change to
Contoso - HR Trainees
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. In a production environment with existing data, do this before users start creating records to avoid ownership surprises.
Morgan, Sam, and Riley 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. You will update this field when setting up hierarchical security later in the post — it just needs to exist.
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 3.
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.
Create the HR Team
Go to Users + permissions → Teams → + Create team.
| Field | Value |
|---|---|
| Team name | HR Team |
| Business Unit | Contoso - HR |
| Team type | Owner |
| Team administrator | Alex |
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 Settings → Users + permissions → Column security profiles → open HR Salary Access → Teams 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(leave Basic User) - Open the
HR Salary AccessColumn 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 (set Department to HR), then 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.
What the Two Options Do
Direct User (Basic) access level and Team privileges — the default. Every team member inherits the role’s privileges as if the role were assigned to them personally. The access level on each privilege applies in full from the individual member’s perspective. With User-level Read, Jordan sees rows Jordan owns. Morgan sees rows Morgan owns. The team membership itself does not widen that scope.
Team Privileges Only — the access level on the privilege is overridden by a team ownership filter. Dataverse stops asking “does this user own the row?” and asks instead “does the team own the row?” Members can only see rows whose owner is the team entity itself, not rows owned by individual members.
The Assign Privilege — Moving a Record to the Team
To demonstrate Team Privileges Only meaningfully, you first need a record owned by the HR Team entity rather than by an individual. That requires the Assign privilege in the Employee Self-Service role.
Go to Security roles → open Employee Self-Service → find the Employee Salary table → set the Assign privilege to User → Save. (User scope means a member can reassign records they personally own.)
Now log in as Jordan. Open the Employee Salary table, select Jordan’s row, and on the command bar choose Assign → Assign to team → select HR Team → OK.
Jordan’s own row is now owned by the HR Team entity. If you refresh as Jordan, that row disappears — Jordan no longer personally owns it, and with Direct User (Basic) access level and Team privileges + User-level Read, Jordan only sees personally owned records. The row has not been deleted; it is simply no longer visible to Jordan under the current setting.
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 reappears — because the owner is the HR Team and Jordan is a member. Open as Morgan: same row is visible for the same reason.
Now create a new row as Morgan, leaving it personally owned by Morgan. Switch to Jordan’s window. Jordan cannot see Morgan’s personal row. It is owned by Morgan, not by the HR Team — and Team Privileges Only only surfaces records the team entity owns.
This is exactly the behaviour Team Privileges Only is designed for. A real example: a shared HR case queue where every incoming case is assigned to the HR Team. Any team member can pick it up, work it, and resolve it — without seeing cases owned by colleagues personally.
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.
Now Jordan and Morgan can see their own personally owned rows again, plus the HR-Team-owned row (because team-owned records are still visible in Direct User mode — the difference is that Direct User additionally surfaces personally owned records).
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 should see their own data.
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:
| Field | Value | Note |
|---|---|---|
| Role Name | Finance Self-Service | |
| Business Unit | Contoso - Finance | Scopes this role to the Finance Business Unit |
| Description | Allows Finance employees to view their own salary records | |
| Applies To | Users and Teams | |
| Member’s privilege inheritance | Direct User (Basic) access level and Team privileges |
Save. Find the Employee Salary table → set Read to User → 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 see 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.
Hierarchical Security — Morgan Sees Jordan’s Row
So far Morgan can only see Morgan’s own rows and the HR-Team-owned row. But Morgan is Jordan’s manager. In a real HR system the team lead should be able to review their reports’ data without needing Organisation-level Read, which would be far too broad.
Dataverse’s Hierarchical Security feature handles this cleanly. When enabled, a manager can read records owned by their direct and indirect reports based on the Manager field on each user record — independently of Business Unit membership.
Set the Manager Field
Go to Users + permissions → Users → open Jordan’s user record → set the Manager field to Morgan → Save.
(Earlier you set Morgan’s Manager to Alex as a placeholder. Leave that as-is — it means Alex is Morgan’s manager, and if you set depth to 2, Alex would also see Jordan’s data. For this demo, keep depth at 1.)
Enable Hierarchical Security
Go to your environment Settings → Users + permissions → Hierarchy security.
Toggle Enable Hierarchy Modelling to On. Leave the model as Manager Hierarchy. Set Depth to 1. Save.
Allow a minute for the change to propagate, then sign Morgan out and back in.
Verify
Open the table as Morgan. Morgan now sees:
- Morgan’s own row (User-level Read, own record)
- Jordan’s row (Hierarchical Security — one level down in the reporting line)
- The HR Team-owned row (team membership)
Open as Jordan. Jordan still sees only their own row and the team-owned row. Hierarchy is one-directional — reports do not gain upward visibility to their manager’s records.
Hierarchical security is read-only by default for managers looking at subordinates’ data. Morgan can see Jordan’s Salary value but cannot edit it through this mechanism. That is almost always the right behaviour for a self-service scenario and is the setting to leave in place.
The Parent:Child BU Access Level
There is one access level the tutorial has not yet demonstrated: Parent:Child BU. You created Contoso - HR Trainees as a child of Contoso - HR and added Riley there for exactly this reason.
The scenario: Riley is a new HR trainee. Morgan, as the HR manager covering both the core team and the trainee sub-group, needs to see records from both BUs. The question is: which access level on Morgan’s role covers that?
| Access level | Covers |
|---|---|
| User | Only Morgan’s own records |
| Business Unit | Contoso - HR users (Jordan, Morgan) — not Riley |
| Parent:Child BU | Contoso - HR and all child BUs, including Contoso - HR Trainees (Riley) |
| Organisation | Every record in the environment — too broad |
Add Riley and Create a Trainee Role
First give Riley a salary row. Log in as Riley (or have Alex create one owned by Riley). Set Department to HR.
Alex creates a HR Trainee Self-Service role: Security roles → + New role → Business Unit: Contoso - HR Trainees → Employee Salary Read: User → Save. Assign it to Riley via Riley’s user record → Manage security roles.
Riley can now see their own row.
Give Morgan Parent:Child BU Read
Create a HR Manager Self-Service role: Security roles → + New role → Business Unit: Contoso - HR → Employee Salary Read: Parent:Child BU → Save. Assign it to Morgan via Morgan’s user record → Manage security roles.
Open the table as Morgan. Morgan now sees:
- Morgan’s own row
- Jordan’s row (in
Contoso - HR, within the Parent:Child scope) - Riley’s row (in
Contoso - HR Trainees, a child BU — also within the Parent:Child scope) - The HR Team-owned row (team membership)
Open as Sam. Sam still sees only Sam’s own Finance row. The BU boundary between Finance and HR holds completely.
What the Access Structure Looks Like Now
| User | Business Unit | Team | Security Role source | Column Profile source | Can see Salary? |
|---|---|---|---|---|---|
| Alex | Root | — | System Administrator (direct) | Bypassed | ✓ Always |
| Jordan | Contoso - HR | HR Team | Employee Self-Service (via team) | HR Salary Access (via team) | ✓ Own row + team row |
| Morgan | Contoso - HR | HR Team | Employee Self-Service (via team) + HR Manager Self-Service (direct) | HR Salary Access (via team) | ✓ Own + Jordan + Riley + team row |
| Riley | Contoso - HR Trainees | — | HR Trainee Self-Service (direct) | None | ✓ Own row only |
| Sam | Contoso - Finance | — | Finance 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. Morgan’s elevated access as team lead is layered on top through an additional role and hierarchical security, both of which scale independently of the team configuration.
Things Worth Knowing
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.
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 is the right setting for shared queue patterns, not self-service. When records belong to the team entity itself and any member should be able to pick them up — a support inbox, an approvals queue, a shared caseload — Team Privileges Only enforces that boundary cleanly. For individual self-service where people should see their own data, keep it on Direct User (Basic) access level and Team privileges.
Hierarchical security does not replace Business Unit access — it adds to it. Morgan can see Jordan’s row via hierarchy regardless of which BU Jordan is in. But it only covers records in the reporting line. It does not grant access to records owned by arbitrary BU colleagues, and it does not cross into other BUs for users outside the reporting chain.
Parent:Child BU access level covers the parent BU and every child BU beneath it — not siblings. If you later add a second child under Contoso - HR, such as Contoso - HR London, Morgan’s Parent:Child BU Read would cover that automatically. Finance data remains completely inaccessible regardless of depth.
Hierarchical security is read-only by default for managers. Morgan can see Jordan’s Salary value but cannot edit it through the hierarchy mechanism. Write access would require the Write privilege to be at least Business Unit level on Morgan’s role, or a separate explicit grant.
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.
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 3 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 3 covers.