macOS: migrating Signal
#macos #signal #migration
SQLite database & its encryption key to a new Mac.
Table of Contents
macOS, really?
Disclaimer: turns out quite a few people across creative communities, from artists to open source developers to die-hard legacy UNIX enthusiasts use macOS as a daily driver. Yes, I know. Not fully open source (though Darwin is and some of the userspace is), but a weird mix of NeXTSTEP, FreeBSD & even some NetBSD code intertwined with Apple’s own free & non-free components. And yet, there are solid uses for it, so without further ado, let’s rock!
Whenever we upgrade Mac hardware, we face the same daunting choice of either:
- use Migration Assistant to get things up & running the quick & dirty way;
- use the new hardware as an opportunity to run a thorough cleaning operation, only transferring what is truly special, leaving years of clutter behind;
While a bunch of stuff are synced through iCloud or syncing $HOME (excluding
~/Library), this is definitely not the case for Signal. Which is problematic to
say the least, since most if not all of the privacy-conscious and/or
technically inclined crowd tend to favor this open source messaging system
over proprietary alternatives.
Why this?
Signal Desktop is a linked device, not a standalone client — it only knows what happened while it was linked to your phone. If you unlink and re-link on a new computer, Signal will sync message history from your phone, but media older than 45 days is permanently gone from Signal’s servers. Text messages transfer fine, but photos, voice notes, and files do not survive beyond that window.
Signal doesn’t officially support desktop-to-desktop transfers — their own backup & restore docs say so. Signal Secure Backups are phone-only and don’t cover desktop data either. But unofficially? That’s what this guide is for.
This means the desktop’s local SQLite database — sitting in
~/Library/Application Support/Signal/sql/db.sqlite — is the only copy of
your full desktop-side history including all media. If you lose it, it’s gone.
Gone: the love letters, the audio poetry, the enthusiastic screenshots. The photo club conversations, the impromptu video declarations. Everything visual, vibrant, precious — everything worth revisiting. These don’t just convey information: they cement relationships, actualize friendships, fuel movements.
So let’s move that database (and its encryption key) to a new Mac, and make Signal pick it up as if nothing changed. Ready?
Prerequisites
- Old Mac reachable via
ssh(set$OLDMACto its hostname, e.g.export OLDMAC=oldmac.local); - Signal Safe Storage key extracted from old Mac (through
security, see below); - Homebrew
rsyncinstalled on the new Mac (macOS ships rsync 2.6.9 from 2006, which lacks flags we need); - Signal is quit on the old Mac (the database is SQLite — copying while Signal writes to it can produce a corrupt copy)
- Signal has never been opened on the new Mac — opening it before migrating will create a fresh identity and registration, making it much harder to restore the old database
Install Signal on the new Mac but do not launch it:
brew install --cask signal
Go!
0. Extract Signal key
On the old Mac:
security find-generic-password \
-s "Signal Safe Storage" \
-w ~/Library/Keychains/login.keychain-db
Save the output (a ~24 character string) to a file:
printf 'Signal Safe Storage\tSignal\t%s\n' \
"$(security find-generic-password \
-s "Signal Safe Storage" \
-w ~/Library/Keychains/login.keychain-db)" \
> ~/migration-secrets.txt
chmod 600 ~/migration-secrets.txt
Transfer to the new Mac:
scp ~/migration-secrets.txt $USER@$NEWMAC:~/migration-secrets.txt
1. Verify
We need to make sure source data exists:
ssh $OLDMAC 'ls -lh ~/Library/Application\ Support/Signal/sql/db.sqlite ~/Library/Application\ Support/Signal/sql/db.sqlite-wal' 2>&1
STOP if db.sqlite is missing. The -wal file may or may not exist (it’s a
SQLite write-ahead log); its absence is fine.
2. Sync
Any network path works here — Wi-Fi, Ethernet, whatever you’ve got. But if you have an Apple Thunderbolt 4 cable, plug it in: macOS automatically creates a Thunderbolt Bridge — a point-to-point network link between the two Macs, no router or switch needed. The cable supports up to 40 Gbps; real-world throughput over rsync/SSH will be lower (expect several Gbps — still dramatically faster than Wi-Fi or gigabit Ethernet, and the fastest Mac-to-Mac direct transfer you can get without Target Disk Mode).
The rsync and ssh flags below are tuned for that kind of bandwidth — on a
slower link they won’t hurt, they’ll just matter less:
$(brew --prefix)/bin/rsync -avPHW \
-e "ssh -c aes128-gcm@openssh.com -o Compression=no" \
--exclude='*Cache*' --exclude='Logs' --exclude='*.log' --exclude='GPUCache' \
$USER@$OLDMAC:Library/Application\ Support/Signal/ \
~/Library/Application\ Support/Signal/
rsync flags explained:
-aarchive mode — preserves permissions, symlinks, timestamps, recurses into directories-vverbose output-Pshows progress per file + enables resuming partial transfers if interrupted-Hpreserves hard links-Wtransfers whole files, skipping the delta/checksum algorithm — faster on high-bandwidth local links where computing diffs costs more than just sending the raw bytes
ssh tuning:
-c aes128-gcm@openssh.comlightweight cipher, reduces CPU overhead on a fast link-o Compression=noskips SSH-level compression — pointless at Thunderbolt speeds and wastes CPU
Verify: ls -lh ~/Library/Application\ Support/Signal/sql/db.sqlite
3. Restore
The keychain key really is where it’s at:
security delete-generic-password \
-s "Signal Safe Storage" \
~/Library/Keychains/login.keychain-db 2>/dev/null
SIGNAL_KEY=$(grep "Signal Safe Storage" ~/migration-secrets.txt | cut -f3)
security add-generic-password \
-a "Signal" -s "Signal Safe Storage" \
-w "$SIGNAL_KEY" ~/Library/Keychains/login.keychain-db
4. Launch
Open Signal. Close your eyes. Drumroll. Open your eyes: you should see your full conversation history with all media. Browse away and go get those precious memories!
If it asks to link/register: QUIT IMMEDIATELY and rollback:
rm -rf ~/Library/Application\ Support/Signal
security delete-generic-password \
-s "Signal Safe Storage" \
~/Library/Keychains/login.keychain-db 2>/dev/null
Then diagnose before retrying — the database or key may be mismatched.
5. Cleanup
If and only if Signal works, as expected:
rm ~/migration-secrets.txt