The TCC access Table Across macOS Versions
How the TCC.db access table changed from Mojave to Big Sur and Sonoma: allowed, auth_value, auth_reason, pid and last_reminded, plus the other tables.
TL;DR. The access table in TCC.db has three broad layouts. Mojave and Catalina: allowed (0/1) and prompt_count. Big Sur (11) and later: auth_value, auth_reason and auth_version replace them, and indirect_object_identifier becomes TEXT NOT NULL DEFAULT 'UNUSED'. Sonoma (14) and later: pid, pid_version, boot_uuid and last_reminded are added. Run .schema access on every copy before querying. TCC Parser reads column names from the schema of each file, so the same view works across releases.
Why the schema matters
Queries and parsers break silently on the wrong layout. A script written for Big Sur that selects auth_value fails on a Catalina database; one written for Catalina that filters on allowed = 1 finds nothing on Sonoma. Plaso's macostcc plugin, for example, requires the pre-Big Sur allowed and prompt_count columns, so it targets Mojave and Catalina databases. Velociraptor's MacOS.System.TCC was written against Big Sur. Check first:
sqlite3 TCC.db '.tables'
sqlite3 TCC.db '.schema access'
Mojave and Catalina (10.14, 10.15)
As documented by Plaso's macostcc plugin, the access table has:
| Column | Notes |
|---|---|
service | TCC service identifier |
client | Bundle ID or absolute path |
client_type | 0 bundle ID, 1 absolute path |
allowed | 1 allowed, 0 not allowed |
prompt_count | How many times the user was prompted |
csreq | Compiled code requirement of the client |
policy_id | Link to policies.id for policy-driven rows |
indirect_object_identifier_type, indirect_object_identifier, indirect_object_code_identity | Target of the grant (Automation) |
flags | Not documented |
last_modified | DEFAULT CAST(strftime('%s','now') AS INTEGER), so Unix seconds, UTC |
The primary key is (service, client, client_type, indirect_object_identifier). That key explains an important behaviour: there is one row per client, service and target, and a new decision replaces the old row rather than adding a new one. The database keeps the current state, not a history.
Big Sur (11) and later
Big Sur replaced allowed and prompt_count with three columns:
| Column | Values |
|---|---|
auth_value | 0 denied, 1 unknown, 2 allowed, 3 limited |
auth_reason | Why the decision was made (see below) |
auth_version | Version of the authorization record format |
indirect_object_identifier became TEXT NOT NULL DEFAULT 'UNUSED', so rows without a target now carry the literal string UNUSED instead of a null. Filter on it when you look for Automation targets.
auth_reason
Apple does not document these values. The mapping below is community-documented and widely used; read it as a hypothesis and confirm on a test Mac of the same version, or against the com.apple.TCC entries in the unified log, before putting it in a report.
| auth_reason | Community interpretation |
|---|---|
| 1 | Error |
| 2 | User consent (answered a prompt) |
| 3 | User set (changed in System Settings) |
| 4 | System set |
| 5 | Service policy |
| 6 | MDM policy |
| 7 | Override policy |
| 8 | Missing usage string |
| 9 | Prompt timeout |
| 10 | Preflight unknown |
| 11 | Entitled |
| 12 | App type policy |
The useful distinction in most cases is between user-driven reasons (2, 3), policy-driven ones (5, 6, 7) and system ones (4, 11, 12). Glossary: auth_value, auth_reason.
Sonoma (14) and later
Sonoma added four columns:
| Column | Notes |
|---|---|
pid | A process ID associated with the row |
pid_version | Accompanies pid |
boot_uuid | Identifies a boot session |
last_reminded | Unix epoch seconds; schema default strftime('%s','now') |
The names suggest the process and boot session involved in the decision, but their exact semantics are not publicly documented. boot_uuid is still handy: it lets you group rows by boot session and compare with other artifacts that record a boot UUID. last_reminded is a second timestamp to put on the timeline; in TCC Parser you can switch the time field between Last modified, Last reminded and Expired at.
Newer releases
We know of no public documentation of access schema changes after Sonoma, including macOS 26 Tahoe. That is exactly why TCC Parser is schema-driven: it reads the column list from each file and decodes the columns it recognizes, instead of assuming a fixed layout per release. If you see a column this article does not mention, check it on a test system before interpreting it.
The other tables
The access table gets all the attention, but the database holds more. In the Mojave/Catalina schema documented by Plaso:
| Table | Columns | What it is for |
|---|---|---|
admin | key, value | Small key/value store; contents not documented |
policies | id, bundle_id, uuid, display | Policies referenced by access.policy_id (for example MDM) |
active_policy | client, client_type, policy_id | Which policy applies to which client |
access_overrides | service (primary key) | Per-service overrides; purpose not documented |
expired | service, client, client_type, csreq, last_modified, expired_at | Grants that expired, with the time they did |
List the tables on your own copy with .tables: later releases may differ. The expired table deserves a look in every case, because it keeps clients that no longer appear in access. Its expired_at is Unix seconds, like last_modified. TCC Parser links policy_id to the policies table and to MDMOverrides.plist, and shows REG.db and any other SQLite file found in the com.apple.TCC folder as raw tables.
One query per layout
Mojave and Catalina:
SELECT service, client, client_type, allowed, prompt_count,
datetime(last_modified, 'unixepoch') AS changed_utc
FROM access ORDER BY last_modified DESC;
Big Sur and later (add last_reminded on Sonoma and later):
SELECT service, client, client_type, auth_value, auth_reason,
NULLIF(indirect_object_identifier, 'UNUSED') AS target,
datetime(last_modified, 'unixepoch') AS changed_utc
FROM access ORDER BY last_modified DESC;
Both return blobs (csreq, indirect_object_code_identity) as raw bytes; decoding them is covered in decoding csreq code requirements.
Timestamps
All timestamps in TCC.db are Unix epoch seconds, UTC: last_modified, last_reminded and expired.expired_at. They are not Mac absolute time, which many other Apple databases use. last_modified is the last write to the row: a prompt answered, a toggle flipped, a policy applied. It is not the first grant.
FAQ
Which macOS version replaced allowed with auth_value in TCC.db?
macOS 11 Big Sur. Mojave and Catalina databases have allowed and prompt_count columns; Big Sur and later have auth_value, auth_reason and auth_version instead.
What columns did Sonoma add to the access table?
macOS 14 Sonoma added pid, pid_version, boot_uuid and last_reminded. last_reminded is Unix epoch seconds, like last_modified.
Are the auth_reason values documented by Apple?
No. The commonly used mapping (1 error, 2 user consent, 3 user set, 4 system set, 5 service policy, 6 MDM policy, 7 override policy, 8 missing usage string, 9 prompt timeout, 10 preflight unknown, 11 entitled, 12 app type policy) comes from community research. Confirm on a test system before relying on it.
Why does my query fail on an older TCC.db?
Because the column you selected does not exist in that schema. Run .schema access first and write the query for the columns that are actually there.