Native Masking — Data Appears Unmasked¶
A column has a Default (or other) masking policy applied in Privacera, and the user or group has only read access with no explicit unmasking policy. When querying the table in SQL Server Management Studio (SSMS) or another SQL client, the data still appears unmasked.
This is usually not a connector apply failure. The login session running the query often has privileges that bypass SQL Server Dynamic Data Masking.
Symptoms¶
- Privacera shows a column-level masking policy (for example Default masking) applied successfully.
- The user and group policies show only SELECT / read access — no unmasking grant in Privacera.
- Querying the masked column in an on-premises SQL Server environment returns the original (unmasked) values.
- PolicySync ACCESS audit shows masking was applied (
MASK/ masking function created on the column).
Explanation¶
SQL Server Dynamic Data Masking hides column values only for principals that do not have bypass privileges. The following principals typically see unmasked data even when a mask is defined on the column:
| Privilege or role | Effect |
|---|---|
sysadmin server role | Full server access; masking is bypassed. |
db_owner database role | Full database access; masking is bypassed. |
UNMASK permission | Explicit permission to see unmasked data (database-level on SQL Server 2019 and earlier; column-level on Azure SQL and SQL Server 2022+). |
Login mapped to dbo | Common when a Windows login is a member of sysadmin — the login maps to the dbo user in each database. |
If you connect to SQL Server with an administrator account (or an account that maps to dbo), you will see unmasked data even though regular users and groups with read-only access see masked values.
Troubleshooting Steps¶
Run the following queries in SSMS while connected with the same login used to reproduce the issue. Replace <database> with the managed database name.
Step 1 — Check the effective login and database user¶
If DatabaseUser is dbo, the session has database-owner-level access and masking is bypassed.
Step 2 — Check for sysadmin membership¶
| SQL | |
|---|---|
A result of 1 means the login is a member of sysadmin and will see unmasked data.
Step 3 — Check database roles for the current user¶
| SQL | |
|---|---|
If the user is a member of db_owner, masking is bypassed.
Step 4 — Check for UNMASK permission¶
Unmasking is database-scoped. Check database-level UNMASK:
| SQL | |
|---|---|
Unmasking can be column-scoped. Check both database-level and column-level UNMASK:
| SQL | |
|---|---|
Replace <schema>.<table>.<column> with the fully qualified masked column name.
Step 5 — Combined diagnostic query¶
| SQL | |
|---|---|
Step 6 — Test masking as a specific non-admin user¶
If Steps 1–5 show admin-level access, impersonate the target user to confirm masking works for that principal:
| SQL | |
|---|---|
After EXECUTE AS USER, masked columns should return obfuscated values (for example XXXX for string default masking). If data is masked under impersonation but unmasked under the original login, the original login has bypass privileges — not a Privacera policy issue.
Note
The user passed to EXECUTE AS USER must exist as a database principal. Use the exact name SQL Server stores (for example LD\pbhele for a Windows-authenticated user). See Deployment and Principal Name Format if names differ between Privacera and SQL Server.
Common Root Causes¶
| Root cause | How to confirm | Resolution |
|---|---|---|
Login is sysadmin | IS_SRVROLEMEMBER('sysadmin') returns 1 | Test with a non-admin account. Ask the DBA to remove unnecessary sysadmin membership for test users. |
Login maps to dbo | USER_NAME() returns dbo | Typical for sysadmin logins. Use a standard user login for masking validation. |
User or group has UNMASK | HAS_PERMS_BY_NAME returns 1 | Check Privacera unmasking policies and manual SQL grants. Revoke UNMASK if the principal should see masked data. See Native Masking and Unmasking Types. |
| Testing with the wrong login | Login name differs from the Privacera policy principal | Connect with the same user or group member account defined in the access policy, not an admin or DBA account. |
Verify Masking Is Applied in SQL Server¶
Confirm the mask exists on the column independently of the querying user:
| SQL | |
|---|---|
If is_masked is 1, the mask is defined in SQL Server. The issue is with the querying principal's privileges, not mask creation.
Recommended Action¶
- Validate masking using a non-admin login that matches the Privacera user or group principal.
- Use
EXECUTE AS USERto confirm masked output for that principal when admin accounts must be used for initial connection. - Work with the customer DBA to review
sysadminmembership andUNMASKgrants for test accounts. - Confirm no unmasking policy exists in Privacera for the user or group under test. On SQL Server 2019 and earlier, unmasking is granted at the database level — a database-level unmask policy affects all columns in that database.
- Prev topic: Troubleshooting