PCI DSS is the one compliance standard whose scope is a table. Somewhere sits a column holding the primary account number (PAN), and the standard asks three questions about it: who can read it, how did they get in, what record is left. Budgets go to segmentation and encryption. To be honest, the findings I see come from access: a readonly login half the company knows, a DBA account without MFA, a reporting job that can SELECT * the cards table, and a log that proves a statement ran but not who ran it.
The cards table is a vault. Requirement 7 decides who gets a key, Requirement 8 checks the key-holder is who the key says, Requirement 10 is the camera over the door. Most teams have a good vault and hand out master keys.
PCI DSS v4.0.1 has been the only active version since the end of 2024. Its 51 future-dated requirements stopped being "best practice" on March 31, 2025, and the database-access ones are graded now.
Where the requirements land
| Requirement | What it says | Where it lands in the database |
|---|---|---|
| 7.2.1 / 7.2.2 | Access by job function, least privilege, default deny | Grants to roles, scoped to the tables a role needs; nobody holds standing access to the cards table |
| 7.2.4 | Review all accounts and privileges at least every six months | A grant inventory you can actually produce, per database |
| 7.2.5 / 7.2.5.1 | System and application accounts get least privilege too, reviewed | The reporting job, the ETL user, the app's own login |
| 8.2.1 / 8.2.2 | Unique ID per user; shared accounts only by exception, with individual accountability | No readonly login on a wiki page |
| 8.3.6 / 8.3.9 | Passwords of 12+ characters, rotated or risk-scored | Database logins too, not just the VPN |
| 8.4.2 | MFA for all access into the cardholder data environment | Every human database session, the DBA's included |
| 8.6.1 / 8.6.2 | Interactive use of system accounts only by exception, approved, time-limited; no hardcoded credentials | "I'll just use the app's creds to debug prod" |
| 10.2.1 | Log all individual user access to cardholder data | Query-level audit tied to the person, not the shared DB user |
| 10.5.1 | Retain logs 12 months, 3 months immediately available | The trail has to survive and stay queryable |
Two of these changed the job in v4. 8.4.2 moves MFA from "admins and remote access" to every account entering the CDE, so the database session needs a second factor, not just the jump host. 7.2.5 and 8.6 put service accounts under the same rules as humans: named, least-privileged, reviewed, never used interactively without a ticket.
What the breaches say
PCI has no public fine table; enforcement runs through the card brands and the numbers stay private. The breaches are public enough.
Target, 2013: an HVAC vendor's stolen login, 40 million cards. The segmentation was incomplete, sure, but the lesson is that a valid credential with broad reach is the whole attack. Scope the key (Requirement 7), make the login prove it's a person (Requirement 8), and the path gets short.
The application account is the widest door in the building. It has to read PAN in the clear, nobody rotates it, nobody reviews it, and everybody borrows it when production misbehaves. 8.6.1 names this: interactive use of a system account needs an exception, an approval, and an expiry. Rules don't change behavior, friction does. If the fastest way to answer a production question is to paste the app's connection string into a client, people will.
"We log everything" is not evidence. 10.2.1 wants a record of each individual's access to cardholder data. Engine-native logging records the database user, so when five analysts share reporting_ro, the log says reporting_ro. The assessor wants a name. Either every human gets a personal login on every engine (hundreds, and you rotate them), or something in front of the database knows the SSO identity and writes it into the record. We hit this gap in our own SOC 2 audit. PCI asks the same question with a one-year clock.
The cheapest control is to have less to protect. Requirement 3 says store PAN only when required and render it unreadable; Requirement 7 says grant only to those who need it. Put simply, most people who query the cards table don't need the card number. Mask it on their path and they drop out of scope for a whole class of findings.
The database work
In the order an assessor will ask:
- Map the CDE at the column level: which databases, tables, and columns hold PAN or enough to reconstruct it. Every control below keys off this list, and so does your scope-reduction argument.
- Grant to roles, never to people: payments app, reconciliation analyst, on-call engineer, DBA. Default deny, and the cards table readable by as few roles as the business can stand.
- Zero standing privilege for humans on production. Elevated access is requested, approved, time-boxed, logged. Same for interactive use of the app's account: an access grant with an expiry, not a shared secret.
- MFA and a name on every session. Tie database access to the SSO identity that already has MFA. Shared logins go away, or a broker wraps them so the shared user on the wire still maps to one human in the log.
- A trail that answers the question: who ran which statement against which CDE table, when, under which approval. Twelve months kept, three queryable without a restore. Test it: pick a date, reconstruct one analyst's day. Longer than an afternoon, fix it before the assessment.
Then put the 7.2.4 review on the calendar: every six months, pull the grant inventory and have each role owner confirm it. The review is exactly as easy as the inventory. When grants live in five engines' system catalogs with no shared view, it becomes a quarter-long spreadsheet and quietly gets skipped.
Where Bytebase fits
Bytebase covers the human-to-database slice. Data classification marks the PAN columns; dynamic masking hides them from anyone querying through the SQL Editor who isn't in a role that needs the clear value. Database permissions are granted by role per project and environment, and a just-in-time access grant is the exception path: one request, one approver, an expiry. Sign-in goes through your SSO, so MFA and the name come along, and the audit log records every query and change under that name, exportable for the year.
Where it stops: Bytebase governs what goes through it. The application's own connection, a DBA shelling into the host, a replica with a BI tool pointed at it, all outside its view. Those need engine-native auditing, network controls, and the Requirement 3 encryption work. A PCI posture needs both layers; Bytebase makes the human one the easy one.
None of this is hard in isolation. Doing it on every engine, for every role, and proving it twelve months later is. Build the column map, grant to roles, time-box the exceptions, keep a trail with names in it. A vault is only as good as its key cabinet.