How to mask PII before using AI on your database

Keep personal and health data out of AI prompts when you ask an assistant about your database: classify columns, mask on every path, and fail closed.

Data protectionUpdated October 25, 2026

Where data leaks

Asking an AI assistant about your database is useful: why a query is slow, what a table holds, how to fix an error. The risk is in what you send with the question. Rows copied into a prompt can include email addresses, card numbers or diagnoses, and those values then leave your machine.

It rarely happens on purpose. It happens through convenient paths:

  • Pasting a result grid into a chat window to ask “why is this wrong?”
  • An assistant connected to the database over MCP that can run its own queries.
  • An export or CSV shared for analysis.
  • Error messages and logs that quote the values that failed.

The goal is simple: the assistant can see structure and safe summaries, and sensitive values stay masked on every one of those paths.

1. Classify columns

You cannot mask what you have not named. List the columns that hold sensitive data and give each a class:

  • PII: names, emails, phone numbers, addresses, national ID numbers.
  • PHI: diagnoses, test results, anything tied to a person's health.
  • Payment: card numbers, bank accounts.
  • Secrets: tokens, password hashes, API keys.

Column names give a first pass. This finds likely candidates; it does not replace a person reviewing the list.

Candidate sensitive columns by namePostgreSQL and SQL Server
SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_schema NOT IN ('pg_catalog', 'information_schema', 'sys')
  AND (   lower(column_name) LIKE '%email%'
       OR lower(column_name) LIKE '%phone%'
       OR lower(column_name) LIKE '%ssn%'
       OR lower(column_name) LIKE '%birth%'
       OR lower(column_name) LIKE '%card%'
       OR lower(column_name) LIKE '%diagnos%')
ORDER BY table_schema, table_name, column_name;

2. Share the schema first, rows only when needed

Most questions an assistant can answer from structure alone: table and column names, types, keys, indexes and the query text. Make that the default. Send row values only when the question truly needs them, and only after masking.

3. Give AI a masked view, not the table

If an assistant or tool needs to query rows, point it at a view that masks sensitive columns, through a role that can read nothing else.

Masked view and a read-only rolePostgreSQL
CREATE VIEW customers_masked AS
SELECT id,
       left(email, 1) || '***@' || split_part(email, '@', 2) AS email,
       'XXXX-' || right(card_number, 4) AS card_last4,
       country,
       created_at
FROM customers;

CREATE ROLE ai_reader LOGIN PASSWORD 'change-me';
GRANT USAGE ON SCHEMA public TO ai_reader;
GRANT SELECT ON customers_masked TO ai_reader;

The assistant connects as ai_reader. It can read customers_masked but not customers, so the raw values are out of reach, not just hidden. Check that nothing grants SELECT on the base table to PUBLIC.

4. SQL Server: Dynamic Data Masking

SQL Server can mask columns for users who lack the UNMASK permission.

Mask columns for non-privileged usersSQL Server
ALTER TABLE dbo.Customers
  ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()');

ALTER TABLE dbo.Payments
  ALTER COLUMN CardNumber ADD MASKED WITH (FUNCTION = 'partial(0,"XXXX-XXXX-XXXX-",4)');

5. Cover every path

Masking in one place and not another is how data still leaks. Check each path:

  • Result grids and cell inspectors.
  • Exports: CSV, Excel, JSON.
  • AI prompts built by any tool you use.
  • MCP tool replies to assistants in your IDE.
  • Error messages and logs that echo values.
  • Support bundles and shared links.

6. Fail closed

The dangerous moment is when masking rules cannot be loaded: a missing config, an expired connection to a policy store. If tools treat “no rules found” as “nothing to mask”, everything flows out.

Make the two states different: no masks configured is a deliberate setting; mask settings unavailable is an error, and in that state nothing should be sent to AI, MCP or exports.

The same rules in Quorum

Quorum applies these rules in the workbench itself, so they hold whichever path the data takes.

Data protection — warehouse-prodenforced · fail closed
Column classification14 rulesper connection · pattern + manual
columnclassexportAI / MCP
Customers.EmailPIImaskednever sent
Patients.DiagnosisPHImaskednever sent
Payments.CardNumberPCIlast 4never sent
Orders.Status—plainschema + values
AI sees: schema · safe summariesrows: offsettings unreadable → nothing leaves
Column classification in Quorum: what each sensitive column shows in exports and to AI or MCP. Illustrative, with synthetic data.
  • Column classification: tag columns as PII, PHI, payment or secret, manually or by pattern, per connection. Enterprise can enforce the rules centrally.
  • Masking on every path: result grid, cell inspector, exports, AI prompts, MCP tool replies, deep links and error logs apply the same rules.
  • What AI sees: schema and safe summaries by default; row values only when you permit them. Choose the provider per workspace, or run fully offline with Ollama.
  • Fail closed: “no masks configured” and “mask settings unavailable” are different states. In the second, AI, MCP and exports release no rows.

Do this in Quorum

Quorum keeps the query, the evidence and the change in one window, across SQL Server, PostgreSQL, MySQL, MongoDB and more. A free 14-day trial is coming soon; request access to hear first.