Data breaches

Data Masking for Test Data: Static vs Dynamic Masking Explained

The NymData teamPublished 6 min read

In short

Data masking replaces sensitive values (names, emails, account numbers) with protected values, so the data stays usable without exposing real people.

Static masking writes a masked copy of the data; dynamic masking hides values on the fly when a query runs, without changing the stored data.

For test and staging environments, the usual approach is a static, masked copy that stays consistent across tables and realistic enough to test with.

The quickest way to reproduce a bug or validate a release is to copy the production database.

The copy is complete, realistic and available right away.

It also contains your customers’ real names, emails, addresses and history.

Data masking is how teams keep the realism of production data without exposing the people in it.

What is data masking?

Data masking replaces sensitive values with protected values that keep the data usable.

A name, an email address or an account number is swapped for something that no longer reveals who the person is.

The table structure, the formats and the relationships stay in place, so applications keep working.

Masking can take several forms:

  1. A type label.
    John Carter becomes [PERSON], and an email becomes [EMAIL]: the value is gone for good.
  2. A realistic pseudonym.
    John Carter becomes another plausible name: the data still reads and behaves like real data.
  3. A constant identifier.
    John Carter becomes PERSON_7b94f21c, and the same identifier comes back every time John Carter appears.

The first is anonymization, the other two are forms of pseudonymization: see pseudonymization vs anonymization for what that changes under the GDPR.

Static vs dynamic data masking

The two terms describe where the masking happens.

Static data masking Dynamic data masking
What changes A separate copy is written with masked values The stored data stays unchanged
When masking happens Once, when the copy is prepared At query time, for each request
Real values on the target server No Yes, hidden from some users
Typical use Test, staging, development, sharing a dataset Restricting what some users see in production

Dynamic masking is a way to control who sees what inside a live system.

Static masking is a way to make sure real values never reach the system in the first place.

For test and staging, static masking is the natural fit: the non-production servers only ever hold masked data.

Why copying production into test is risky

A production database benefits from strict controls: restricted access, encryption, monitoring.

Its copies, much less so.

  1. They are less protected.
    A test server is often set up quickly, with looser access rules, because it is seen as non-critical.
  2. More people can reach them.
    Developers, testers, QA teams and outside contractors all need access to do their jobs.
  3. They multiply.
    Test, QA, staging, pre-production, SQL dumps on a laptop, exports for a migration: every copy widens the exposure.
  4. They get forgotten.
    A dump made to fix a bug stays on an internal server, unencrypted, and a server meant to run for a few days is still online months later.

Real cases show the pattern.

In 2019, more than 540 million records about Facebook users ended up publicly accessible on misconfigured Amazon servers, stored by a third party, Cultura Colectiva.

Between 2017 and 2021, thousands of Elasticsearch databases were found open on the internet, including test environments, staging servers and internal dumps.

The common thread: copies of real data, outside the main environment and less protected than it.

What privacy rules expect from test data

The GDPR makes no difference between production and test.

  1. Data minimization (Article 5).
    Data must be limited to what is necessary, and testing a form does not require the real customer file.
  2. Data protection by design (Article 25).
    Protection must be built in during development, not added afterwards.
  3. Security of processing (Article 32).
    Measures must match the risk, copies included, and the GDPR names pseudonymization among them.
  4. Breach notification (Articles 33 and 34).
    An exposed staging server is a personal data breach like any other.

US teams face the same question under state privacy laws such as the CCPA.

The columns teams forget to mask

Columns called name or email are rarely missed.

Exposures come through the others.

  1. Free-text fields.
    Notes, comments, descriptions: “Call Mrs. Carter back at (555) 013-2847” or “see [email protected]”.
  2. Logs and metadata.
    last_login_ip, user_agent, created_by, session_token: IP addresses, emails and identifiers.
  3. Poorly named technical columns.
    field_7, custom_attr_3, extra_info: they can hold an account number, an SSN or sensitive JSON.
  4. Combinations of ordinary fields.
    ZIP code, date of birth and occupation can identify someone together, so generalize them or leave them out if the test does not need them.
  5. File paths and attachments.
    /uploads/resumes/john-carter-resume.pdf: the name is in the path.

How to mask test data, step by step

  1. Map before you copy.
    Scan every column, names and values, free text included, to know where the PII is.
  2. Copy only what the test needs.
    A subset of rows or tables is often enough, and unused columns stay behind.
  3. Anonymize what does not need to be tracked.
    A type label such as [PERSON], [EMAIL] or [IBAN] replaces the value irreversibly.
  4. Mask consistently what must stay linked.
    With a constant identifier, John Carter is PERSON_7b94f21c in customers, orders and tickets, so joins still work.
  5. Keep the data realistic.
    Realistic pseudonyms keep plausible values, so screens and business rules behave as they do in production.
  6. Never modify the source database.
    The masked data is written to a separate target database, and production stays intact.
  7. Keep a record.
    A report of what was detected and what was done documents the process for an audit.

With NymData

NymData connects to your PostgreSQL and MySQL databases, on your own servers, and writes a masked copy for test, QA or staging.

  1. Mapping.
    A scan of the database that changes nothing, with a report of the sensitive data found, available before any action.
  2. One method per column.
    Anonymization, realistic pseudonymization or constant identifier, depending on how each column is used.
  3. Consistency across tables and files.
    The same value gets the same identifier in every table, and in the project’s Word, Excel and CSV files.
  4. Source database untouched.
    The result is inserted into a target database, with a SQL filter and a row limit to copy only what is needed.
  5. Scheduled refreshes.
    A filter on the modification date (updated_at > '${LAST_JOB_DATE}') picks up only the rows changed since the last run, with an audit report for each run.

See how it works on the data masking page, or request a demo.

Frequently asked questions

What is data masking?

Data masking replaces sensitive values with protected ones, such as a type label, a realistic fake name or a consistent identifier.

The goal is data that still works for testing, development or analytics, without exposing the real people behind it.

What is the difference between static and dynamic data masking?

Static masking produces a separate copy of the data in which sensitive values have been replaced.

Dynamic masking leaves the stored data unchanged and hides values at query time, depending on who is asking.

For test and staging environments, a static masked copy keeps real values out of the non-production servers.

Can you use production data in a test environment?

Under the GDPR, personal data is personal data on any server, and a test rarely needs real identities.

The recommended practice is to anonymize or pseudonymize the data before it leaves production.

How do you keep masked test data consistent across tables?

Use a constant identifier: the same original value always gets the same replacement, for example PERSON_7b94f21c.

Customers, orders and tickets then still join correctly after masking.

How do you keep test data realistic after masking?

Keep the structure, the formats and the relationships between tables.

Realistic pseudonymization replaces John Carter with another plausible name, so screens and processes behave as they do in production.

Learn moreMask a PostgreSQL or MySQL database →Sensitive columns detected, anonymized copy written to a test database, source database never modified.
Request a demo