100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Masking Policies and Row Access Policies

How Snowflake dynamically hides sensitive column values or entire rows from unauthorized roles, enforced consistently at query time across every downstream consumer.

Data Sharing & GovernanceAdvanced10 min readJul 10, 2026
Analogies

Dynamic Data Masking with Column Masking Policies

A masking policy is a schema-level object created with CREATE MASKING POLICY that defines, via a SQL expression, how a column's value should be transformed based on the querying role, then attached to one or more columns with ALTER TABLE ... MODIFY COLUMN ... SET MASKING POLICY. Because the policy is evaluated dynamically at query time rather than by altering stored data, the same underlying value can appear fully visible to a privileged role and redacted or hashed to an unprivileged role, and the policy automatically applies everywhere the column is used, including views, joins, and cloned tables.

🏏

Cricket analogy: It's like a broadcaster's live feed showing full player biometric data to the team's own medical staff but blurring that same overlay to the general TV audience.

Row Access Policies for Row-Level Security

A row access policy is a schema-level object created with CREATE ROW ACCESS POLICY that defines a boolean expression evaluated per row, typically checking the current role or a session context against a mapping table, and is attached to a table with ALTER TABLE ... ADD ROW ACCESS POLICY. Rows for which the expression evaluates to false are silently excluded from query results for that role, so a single physical table can serve multiple business units or regions with each seeing only their own rows, again without maintaining separate filtered copies of the data.

🏏

Cricket analogy: It's like a single central fixtures database where each franchise's team management only sees rows for their own squad's matches, filtered live by their login, not by separate spreadsheets per team.

sql
-- Column masking: hash SSNs for anyone except the privileged role
CREATE MASKING POLICY ssn_mask AS (val STRING) RETURNS STRING ->
  CASE
    WHEN CURRENT_ROLE() IN ('COMPLIANCE_ADMIN') THEN val
    ELSE 'XXX-XX-' || RIGHT(val, 4)
  END;

ALTER TABLE employees MODIFY COLUMN ssn
  SET MASKING POLICY ssn_mask;

-- Row access policy: each region only sees its own rows
CREATE ROW ACCESS POLICY region_policy AS (region STRING) RETURNS BOOLEAN ->
  CURRENT_ROLE() = 'GLOBAL_ANALYST'
  OR EXISTS (
    SELECT 1 FROM region_role_map
    WHERE region_role_map.role_name = CURRENT_ROLE()
      AND region_role_map.region = region
  );

ALTER TABLE sales_by_region
  ADD ROW ACCESS POLICY region_policy ON (region);

Applying Governance Consistently Across Clones and Shares

Because masking and row access policies are evaluated at query execution time rather than baked into stored bytes, they travel with the object: a zero-copy clone of a masked table retains the same masking policy, and a table shared via Secure Data Sharing continues to enforce it for the consuming account's roles, provided the consumer maps its roles appropriately or the policy logic accounts for cross-account context. This makes policies the correct governance layer for combining with cloning and sharing features, since re-implementing row filters or masking logic in downstream views would be far more error-prone and easy to bypass.

🏏

Cricket analogy: It's like a stadium's access-control rule following the turnstile system to a brand-new satellite venue, rather than needing separate rules configured at every stadium.

Masking and row access policies can be inspected with SHOW MASKING POLICIES, SHOW ROW ACCESS POLICIES, and by querying the POLICY_REFERENCES table function, which lists every object a given policy is currently attached to — useful for auditing coverage before a compliance review.

A masking policy hides displayed values but does not prevent an unprivileged role from inferring sensitive data through aggregate functions, GROUP BY on masked-adjacent columns, or joins against other unmasked tables. Combine masking policies with row access policies and careful grant scoping for genuinely sensitive datasets rather than relying on masking alone.

  • Masking policies dynamically transform column values at query time based on the querying role, without altering stored data.
  • The same masked column can show full values to privileged roles and redacted values to others, consistently everywhere it's used.
  • Row access policies define a boolean per-row expression, silently filtering out rows a role shouldn't see.
  • A single physical table can serve many business units or regions safely under one row access policy.
  • Policies are evaluated at query time, so they travel automatically with zero-copy clones and shared objects.
  • POLICY_REFERENCES and SHOW commands let you audit exactly which objects a policy currently protects.
  • Masking alone can be circumvented via aggregation or joins, so combine it with row access policies and tight grants.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#SnowflakeStudyNotes#MaskingPoliciesAndRowAccessPolicies#Masking#Policies#Row#Access#StudyNotes#SkillVeris#ExamPrep