Skip to content

Communications

WhatsApp on Android: msgstore.db and wa.db

WhatsApp's Android databases and backups: msgstore.db message and chat tables, wa.db contacts, crypt14 and crypt15 backups, media paths and deleted messages.

Location
/data/data/com.whatsapp/databases/msgstore.db
Proves
WhatsApp chats and groups, message text, direction, sender, sent and received times, media, calls, and contact names of chat partners
Timestamps
Unix milliseconds (UTC): message.timestamp, received_timestamp, receipt tables, chat.created_timestamp, call_log.timestamp
Access
Full file system (root, exploit or agent); credential-encrypted sandbox, so AFU only. Logical: only encrypted local backups and media in shared storage, plus user chat exports. ADB backup only via an APK downgrade method.
Retention
Until the user deletes messages or chats, disappearing-message timers expire, or the app is removed; local backups rotate (usually about 7 daily copies)
Collection
Full file system extraction, adb pull of /sdcard/Android/media/com.whatsapp, Chat export (user), APK downgrade (alters device)
  • Messaging Forensics: Android SMS: reads the sms table of mmssms.db (not MMS parts) and SMS Backup & Restore XML, which also carries MMS and calls. WhatsApp: needs a decrypted msgstore.db, not a .crypt14/.crypt15 backup. Telegram and Signal support covers their desktop apps only.

What it is

WhatsApp for Android keeps its entire message history in a local SQLite database, msgstore.db, and its view of the user's contacts in wa.db. Messages are end-to-end encrypted in transit, but on the phone the database itself is plain SQLite inside the app sandbox, protected only by Android's file-based encryption. WhatsApp also writes encrypted copies of the database to shared storage every night (msgstore.db.crypt14 or .crypt15) and, if the user enabled it, to Google Drive.

WhatsApp Business (com.whatsapp.w4b) uses the same layout under its own package name.

Where it lives

ItemPathNotes
Messages/data/data/com.whatsapp/databases/msgstore.db (+ -wal, -shm)Chats, messages, media metadata, receipts, calls
Contacts/data/data/com.whatsapp/databases/wa.dbwa_contacts: JIDs, names, about text
Other databasesaxolotl.db, chatsettings.dbSignal-protocol key material, per-chat settings
Backup key (crypt14)/data/data/com.whatsapp/files/keyDecrypts local .crypt14 backups
Preferences/data/data/com.whatsapp/shared_prefs/Registered number, settings, backup configuration
Local backups/sdcard/Android/media/com.whatsapp/WhatsApp/Databases/msgstore.db.crypt14 / .crypt15 and dated copies msgstore-YYYY-MM-DD.1.db.crypt14; before the 2021 scoped-storage move: /sdcard/WhatsApp/Databases/
Media/sdcard/Android/media/com.whatsapp/WhatsApp/Media/Images, Video, Voice Notes, Documents, .Statuses

The sandbox paths are the same on Android 8 to 16; the shared-storage location depends on the WhatsApp version rather than the Android version.

What it proves

  • The chats and groups on the device (chat, with group subject), the messages in each, and whether each was sent by the device owner (from_me = 1).
  • The sender of each group message (sender_jid_row_id → jid), the message text (text_data) and its type (text, image, voice note, document, location, system event).
  • When a message was sent and when this device received it, and on outgoing messages when recipients received, read or played it (receipt tables).
  • Media sent or received (file path, MIME type, size, and caption through the message text) and WhatsApp voice and video calls (call_log table).
  • That a message was deleted for everyone: a revoked placeholder row remains even though the text is gone.

It does not prove who held the phone, and the contact names in wa.db come from the address book or the partner's own profile name, not from WhatsApp verification.

Key fields

TableColumnsMeaning
messagechat_row_id, from_me, key_id, sender_jid_row_id, timestamp, received_timestamp, message_type, text_data, starredOne row per message (current schema)
chat_id, jid_row_id, subject, created_timestamp, archived, hiddenConversations and groups
jid_id, user, server, raw_stringIdentifiers: <number>@s.whatsapp.net, <id>@g.us for groups, @lid on newer builds
message_mediamessage_row_id, file_path, mime_type, file_size, media_nameAttachments; a caption is stored as the message's text_data
call_logjid_row_id, from_me, timestamp, video_call, duration, call_resultWhatsApp calls
messages (legacy)key_remote_jid, key_from_me, data, timestamp, media_wa_type, remote_resourcePre-2022 schema, still found on old backups and devices
wa_contacts (wa.db)jid, display_name, wa_name, status, is_whatsapp_userContact book as WhatsApp sees it

Table and column names drift between WhatsApp releases: confirm them with .schema on the database you have before trusting a saved query.

Timestamps

All WhatsApp times are Unix epoch milliseconds in UTC.

SELECT m._id, cj.raw_string AS chat, c.subject,
       CASE m.from_me WHEN 1 THEN 'owner' ELSE sj.raw_string END AS sender,
       datetime(m.timestamp/1000, 'unixepoch')          AS sent_utc,
       datetime(m.received_timestamp/1000, 'unixepoch') AS received_utc,
       m.message_type, m.text_data
FROM message m
JOIN chat c      ON c._id = m.chat_row_id
LEFT JOIN jid cj ON cj._id = c.jid_row_id
LEFT JOIN jid sj ON sj._id = m.sender_jid_row_id
ORDER BY m.timestamp;

timestamp is the send time as reported to this device; received_timestamp is when this handset stored it. A long gap means the phone was offline.

Retention

Messages stay until the user deletes them, clears or deletes the chat, or a disappearing-messages timer removes them (24 hours, 7 days or 90 days). "Delete for everyone" leaves a revoked row. Uninstalling the app deletes the sandbox, but the local backups and media in shared storage survive unless the user removes them. Local backups are written nightly and old dated copies are rotated. Deleted rows often remain in the WAL and in free pages of msgstore.db.

Collection

  • Full file system extraction (AFU) is the reliable route to msgstore.db, wa.db, the key file and the WAL.
  • Logical: pull the local backups and media with adb pull /sdcard/Android/media/com.whatsapp/. A .crypt14 backup needs the key file from the sandbox; a .crypt15 end-to-end encrypted backup needs the 64-digit key or, via WhatsApp's servers, the user's password.
  • APK downgrade: replacing WhatsApp with an old version that allows adb backup, then restoring the current one. It changes the device and can fail; Android 14 and later block installing very old target SDK APKs unless adb install --bypass-low-target-sdk-block is used. Document it fully if used.
  • Chat export: the user can export a chat as .txt (with or without media) from the app.

Parsing

  • Messaging Forensics reads a decrypted msgstore.db (current and legacy schemas) with wa.db for contact names, replays the WAL, and also opens chat export .txt/.zip files, entirely in the browser.
  • wa-crypt-tools decrypts .crypt12, .crypt14 and .crypt15 backups when you have the key.
  • ALEAPP and the commercial suites parse messages, media, calls and group participants, and some carve deleted records.

Investigator tips

  • Always resolve JIDs through wa.db and the device contacts; @lid identifiers on newer builds are not phone numbers.
  • Compare the newest local backup with the live database: messages deleted after the last nightly backup are often still in the backup.
  • Media files are named with the date they were saved (IMG-20260914-WA0003.jpg); the name date, the file's timestamps and message_media rows should agree.
  • WhatsApp voice calls are in call_log inside msgstore.db, not in the Android call log.
  • Use usagestats to show WhatsApp was in the foreground when a message was typed, and installed packages for its install and update dates.

See also