Snowflake

Masking Policy vs Row Access Policy: 8-Point Comparison

2026-03-26
更新: 2026-03-27
NicheeLab Editorial Team

Snowflake's two core data-protection features, Masking Policy and Row Access Policy, are both policy-based access controls available on Enterprise Edition and above, but they target fundamentally different things. Masking Policy transforms the value of a column, while Row Access Policy filters the visibility of rows. Using both correctly — and combining them when needed — is required knowledge for the SnowPro Security exam and for real-world deployments.

8-Point Comparison Table

DimensionMasking PolicyRow Access Policy
Target of controlColumn value (transforms column values)Row visibility (filters records)
Return typeSame data type as input (returns masked value)BOOLEAN (TRUE = visible / FALSE = hidden)
Attach targetOne per columnOne per table or view
Behavior with SELECT *Masked values are returnedOnly filtered rows are returned
Impact on COUNT(*)No impact (row count is unchanged)Returns the post-filter row count
Behavior in WHERE clauseFiltering runs against pre-mask valuesWHERE clause is applied after the policy filter
Tag-based applicationAuto-applied via ALTER TAG SET MASKING POLICYAuto-applied via ALTER TAG SET ROW ACCESS POLICY
Required privilegesCREATE MASKING POLICY + APPLY MASKING POLICYCREATE ROW ACCESS POLICY + APPLY ROW ACCESS POLICY

Masking Policy Implementation Example

-- Mask email addresses
CREATE OR REPLACE MASKING POLICY mask_email
  AS (val VARCHAR) RETURNS VARCHAR →
  CASE
    WHEN IS_ROLE_IN_SESSION('HR_ADMIN') THEN val
    WHEN IS_ROLE_IN_SESSION('MANAGER') THEN
      CONCAT(LEFT(val, 2), '****@', SPLIT_PART(val, '@', 2))
    ELSE '****@****.***'
  END;

-- Attach to a column
ALTER TABLE hr.employees
  ALTER COLUMN email
  SET MASKING POLICY mask_email;

-- Numeric salary masking
CREATE OR REPLACE MASKING POLICY mask_salary
  AS (val NUMBER) RETURNS NUMBER →
  CASE
    WHEN IS_ROLE_IN_SESSION('HR_ADMIN') THEN val
    WHEN IS_ROLE_IN_SESSION('MANAGER') THEN
      ROUND(val, -4)  -- Round to nearest 10,000
    ELSE NULL
  END;

ALTER TABLE hr.employees
  ALTER COLUMN salary
  SET MASKING POLICY mask_salary;

Row Access Policy Implementation Example

-- Department-based row filter
CREATE OR REPLACE ROW ACCESS POLICY rap_department
  AS (dept_val VARCHAR) RETURNS BOOLEAN →
  IS_ROLE_IN_SESSION('HR_ADMIN')
  OR dept_val = (
    SELECT department FROM hr.user_dept_mapping
    WHERE user_name = CURRENT_USER()
  );

-- Attach to the table
ALTER TABLE hr.employees
  ADD ROW ACCESS POLICY rap_department ON (department);

Combined Application Pattern

A Masking Policy and a Row Access Policy can be applied to the same table simultaneously. In that case, they are evaluated in the order Row Access Policy → Masking Policy.

-- Scenario: apply both to the hr.employees table
-- Row Access Policy: only show employees in the user's own department
-- Masking Policy: mask the salary column depending on the role

-- Step 1: attach the Row Access Policy
ALTER TABLE hr.employees
  ADD ROW ACCESS POLICY rap_department ON (department);

-- Step 2: attach the Masking Policies
ALTER TABLE hr.employees
  ALTER COLUMN salary
  SET MASKING POLICY mask_salary;

ALTER TABLE hr.employees
  ALTER COLUMN email
  SET MASKING POLICY mask_email;

-- Result (for the MANAGER role):
-- 1. Row Access Policy narrows the result to the user's own department
-- 2. salary column is rounded to the nearest 10,000
-- 3. email column is returned as the first 2 characters plus a masked suffix

When to Use Secure Views Instead

DimensionMasking / Row Access PolicySecure View
ScopeApplies to every access path to the tableOnly access through the view
Hiding the view definitionPolicy logic is visible only to the ownerView definition is hidden from GET_DDL
Optimizer behaviorStandard optimizations applySome optimizations are restricted
Management costManaged via table + policyMay require a separate view per role
Compatibility with Data SharingPolicies remain effective for consumersSecure Views are recommended for Data Sharing

Design Decision Guide

Requirement: restrict data for specific users or roles
│
├─ Restrict at the row level (e.g., show only employees in the user's department)
│   └─ → Row Access Policy
│
├─ Transform column values before returning (e.g., mask part of an SSN)
│   └─ → Masking Policy
│
├─ Completely hide a column
│   ├─ Drop the column from query results → Projection Policy
│   └─ Drop the column from a view       → Secure View
│
└─ Both row restriction + column masking
    └─ → Combine Row Access Policy + Masking Policy

Pitfalls and Caveats

  • Masking Policy and the WHERE clause: A Masking Policy applies when query results are returned, but WHERE clause filters run against the pre-mask values. In other words, SELECT email WHERE email = '[email protected]' evaluates the WHERE condition against the original value even though the returned email is masked.
  • Row Access Policy and COUNT: When you run COUNT(*) on a table with a Row Access Policy, it returns the post-filter row count. A user who knows the total row count through another channel could infer how many rows are hidden from them.
  • Debugging policies: The owner role can inspect policy logic with DESCRIBE MASKING POLICY / DESCRIBE ROW ACCESS POLICY. Always validate the intended behavior with a test role before rolling out to production.
  • Conditional Masking: By passing multiple columns into a Masking Policy, you can vary the masking based on other column values (for example, unmask only when region equals APAC).

Conditional Masking

-- Switch masking based on the value of another column
CREATE OR REPLACE MASKING POLICY mask_salary_by_region
  AS (salary_val NUMBER, region_val VARCHAR) RETURNS NUMBER →
  CASE
    WHEN IS_ROLE_IN_SESSION('HR_ADMIN') THEN salary_val
    WHEN IS_ROLE_IN_SESSION('APAC_MANAGER')
      AND region_val = 'APAC' THEN salary_val
    ELSE NULL
  END;

-- Attach by mapping the two columns
ALTER TABLE hr.employees
  ALTER COLUMN salary
  SET MASKING POLICY mask_salary_by_region
  USING (salary, region);

Check Your Understanding

Security & Governance

問題 1

The hr.employees table has both a Row Access Policy (showing only the user's own department via the department column) and a Masking Policy (NULL-ing the salary column) applied simultaneously. A user with ANALYST_ROLE (Engineering department) runs SELECT department, salary, COUNT(*) OVER() FROM hr.employees. Which result is correct?

  1. All departments' employees are shown, salary is NULL, and COUNT(*) shows the entire table's row count
  2. Only Engineering department employees are shown, salary is NULL, and COUNT(*) shows the Engineering department's row count
  3. Only Engineering department employees are shown, salary shows the original values, and COUNT(*) shows the Engineering department's row count
  4. The query errors out (because Row Access Policy and Masking Policy cannot be applied at the same time)

正解: B

Row Access Policy and Masking Policy can be applied simultaneously. The Row Access Policy is evaluated first, leaving only the Engineering department rows. The Masking Policy is then applied, converting the salary column to NULL. COUNT(*) OVER() returns the row count after the Row Access Policy is applied (the Engineering department's row count). This evaluation order (Row Access → Masking) is enforced internally by Snowflake.

Frequently Asked Questions

When both a Masking Policy and a Row Access Policy are applied, which is evaluated first?

Snowflake evaluates the Row Access Policy first, then applies the Masking Policy to rows that pass the filter. This order is hard-coded inside Snowflake and cannot be changed by users. For example, if a row is filtered out by the Row Access Policy, the Masking Policy for that row is never evaluated (since the row itself is not in the result set).

Should permissions for Masking Policy and Row Access Policy be separated?

Yes. In Snowflake, APPLY MASKING POLICY and APPLY ROW ACCESS POLICY are managed as separate privileges. Separating policy OWNERSHIP (create/modify rights) from APPLY (table-attach rights) enables proper separation of duties. For example, the security team can create policies (OWNERSHIP) while data engineers apply them to individual tables (APPLY).

Can a Secure View replace Masking Policy or Row Access Policy?

Secure Views can exclude columns or filter rows in a WHERE clause, but they have no effect when the underlying table is queried directly or accessed via paths other than the view. Masking Policy and Row Access Policy are attached to the table itself, so they apply to all access paths: direct queries, views, stored procedures, and more. Use Secure Views when you need to hide the view definition, but design your data protection strategy primarily around policies.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Snowflake

Snowflake Certifications: All 11 Exams Explained (2026)

Every SnowPro certification — Associate, Core, Specialty, Ad...

Snowflake

Snowflake Exam Difficulty Ranking: All 11 Certs Compared (2026)

All 11 SnowPro exams ranked by difficulty with study-time es...

Snowflake

Snowflake Study Guide: Fastest Pass Route by Exam (2026)

How to pass SnowPro certifications efficiently — official ma...

Snowflake

SnowPro Core (COF-C03): Complete Exam Guide (2026)

Pass the SnowPro Core exam — six domains, scope, sample ques...

Snowflake

SnowPro Associate Platform (SOL-C01): Complete Guide (2026)

The entry-level SnowPro Associate exam — scope, weighting, s...

Browse all Snowflake articles (103)
© 2026 NicheeLab All rights reserved.