The 'Bad passphrase' error occurs when Git attempts to sign a commit or tag using GPG, but the passphrase provided (or cached) for your GPG key is incorrect. This typically happens when the GPG agent cache has expired, the passphrase was entered incorrectly, or macOS Keychain has stored an invalid passphrase.
This error indicates that GPG (GNU Privacy Guard) attempted to use your private signing key but was unable to unlock it because the passphrase verification failed. When you configure Git to sign commits or tags, it uses your GPG key to create a cryptographic signature. This key is protected by a passphrase that you set when you created the key. The GPG agent caches your passphrase for a limited time (typically 10 minutes to 2 hours depending on configuration). When this cache expires, GPG needs you to re-enter the passphrase. However, if the terminal or application cannot display the passphrase prompt (pinentry), or if an incorrect passphrase has been cached, you'll see this error. Common scenarios that trigger this error: 1. **Cache expired** - The passphrase cache timed out and GPG couldn't prompt you for re-entry 2. **Wrong passphrase in keychain** - macOS Keychain or another credential store has an incorrect passphrase saved 3. **TTY issues** - GPG's pinentry program cannot connect to your terminal to ask for the passphrase 4. **Headless environment** - Running Git in a CI/CD pipeline or SSH session without a proper TTY
The most common fix is to manually trigger GPG to ask for your passphrase. This refreshes the cache and ensures the correct passphrase is stored:
# Create a temporary file and sign it to trigger passphrase prompt
echo "test" | gpg --clearsign
# Enter your correct passphrase when prompted
# If successful, you'll see signed output
# If the passphrase is wrong, you'll see the same errorIf you don't remember your passphrase or it's not working:
1. The passphrase was set when you created the GPG key
2. It's NOT your system password or GitHub password
3. If you've truly forgotten it, you'll need to create a new GPG key
After successfully entering your passphrase, try your Git commit again:
git commit -m "Your commit message"GPG needs to know which terminal to use for displaying the passphrase prompt. If GPG_TTY is not set, the pinentry program may fail silently:
# Set GPG_TTY for current session
export GPG_TTY=$(tty)
# Verify it's set correctly
echo $GPG_TTY
# Should output something like /dev/ttys001 or /dev/pts/0Make it permanent by adding to your shell configuration:
For Bash (~/.bashrc or ~/.bash_profile):
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
source ~/.bashrcFor Zsh (~/.zshrc):
echo 'export GPG_TTY=$(tty)' >> ~/.zshrc
source ~/.zshrcFor Fish (~/.config/fish/config.fish):
set -x GPG_TTY (tty)After setting this, restart your terminal and try your commit again.
The GPG agent may be in a corrupted state or holding onto an invalid passphrase. Restarting it clears the cache and forces a fresh passphrase prompt:
# Kill the running GPG agent
gpgconf --kill gpg-agent
# The agent will restart automatically on next use
# Alternatively, start it manually
gpg-agent --daemonAlternative methods:
# Using pkill (Linux/macOS)
pkill gpg-agent
# Using killall (macOS)
killall gpg-agent
# Force reload of all GPG components
gpgconf --kill allAfter restarting, try signing something to trigger a fresh passphrase prompt:
echo "test" | gpg --clearsignThen retry your Git operation.
The pinentry program handles the passphrase prompt dialog. If it's misconfigured, you may not see the prompt at all:
Check your current pinentry:
# See which pinentry is configured
cat ~/.gnupg/gpg-agent.conf
# Find available pinentry programs
which pinentry pinentry-tty pinentry-curses pinentry-macFor terminal-based environments (Linux/SSH):
# Use TTY-based pinentry
echo "pinentry-program /usr/bin/pinentry-tty" >> ~/.gnupg/gpg-agent.conf
# Or use curses-based pinentry
echo "pinentry-program /usr/bin/pinentry-curses" >> ~/.gnupg/gpg-agent.conf
# Restart the agent
gpgconf --kill gpg-agentFor macOS with GUI:
# Install pinentry-mac via Homebrew
brew install pinentry-mac
# Configure GPG to use it
echo "pinentry-program $(which pinentry-mac)" >> ~/.gnupg/gpg-agent.conf
# Restart the agent
killall gpg-agentFor Linux with GUI (GNOME):
# Use GNOME pinentry
echo "pinentry-program /usr/bin/pinentry-gnome3" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agentMake sure to remove any duplicate pinentry-program lines in your config.
On macOS, an incorrect passphrase may be stored in Keychain Access. This cached bad passphrase will cause repeated failures:
Method 1: Using Keychain Access app:
1. Open Keychain Access (search in Spotlight)
2. Search for "GnuPG" or "gpg" in the search bar
3. Look for entries related to your GPG key
4. Right-click and select Delete or update the password
Method 2: Using command line:
# List keychain items related to GPG
security find-generic-password -l "GnuPG" 2>/dev/null
# Delete GPG-related keychain entries
security delete-generic-password -l "GnuPG" 2>/dev/nullMethod 3: Reset pinentry-mac cache:
# Kill gpg-agent to clear its cache
killall gpg-agent
# Remove pinentry-mac's saved passwords
# Look in Keychain Access for entries containing your key IDAfter clearing the keychain, your next GPG operation will prompt for the passphrase again. Make sure to enter it correctly this time, and optionally check "Save in Keychain" only if you're confident it's correct.
Ensure Git is configured to use the correct GPG key:
# List your secret keys
gpg --list-secret-keys --keyid-format=long
# Output will show something like:
# sec rsa4096/ABC123DEF456GH78 2023-01-15 [SC]
# 1234567890ABCDEF1234567890ABCDEF12345678
# uid [ultimate] Your Name <[email protected]>
# ssb rsa4096/09876FEDCBA54321 2023-01-15 [E]The key ID is the part after the algorithm (e.g., ABC123DEF456GH78).
Check Git's signing key configuration:
# See current signing key
git config --global user.signingkey
# Set the correct key if needed
git config --global user.signingkey ABC123DEF456GH78
# Verify GPG program path
git config --global gpg.program
# Should output: gpg or /usr/bin/gpg or /usr/local/bin/gpgTest the key directly:
# Test signing with the specific key
echo "test" | gpg --local-user ABC123DEF456GH78 --clearsignIf this test fails with "Bad passphrase", the issue is definitely with your passphrase entry, not Git's configuration.
If you need to make commits urgently while troubleshooting, you can temporarily disable signing:
Disable signing for a single commit:
git commit --no-gpg-sign -m "Your commit message"
# Or use the short flag
git commit -S- -m "Your commit message"Disable signing globally (temporary):
# Turn off commit signing
git config --global commit.gpgsign false
# Turn off tag signing
git config --global tag.gpgsign false
# Re-enable later
git config --global commit.gpgsign true
git config --global tag.gpgsign trueDisable for a specific repository:
# In the repository directory
git config commit.gpgsign falseNote: Unsigned commits may not be accepted by repositories that require signed commits. This is only a temporary workaround while you fix the underlying GPG issue.
Adjust how long GPG caches your passphrase to reduce how often you need to re-enter it:
Edit ~/.gnupg/gpg-agent.conf:
# Create or edit the config file
nano ~/.gnupg/gpg-agent.confAdd these settings:
# Cache passphrase for 8 hours (28800 seconds)
default-cache-ttl 28800
# Maximum cache time regardless of activity (24 hours)
max-cache-ttl 86400
# For SSH keys (if using GPG agent for SSH)
default-cache-ttl-ssh 28800
max-cache-ttl-ssh 86400Apply the changes:
gpgconf --kill gpg-agentDefault values:
- default-cache-ttl: 600 seconds (10 minutes)
- max-cache-ttl: 7200 seconds (2 hours)
Setting longer timeouts means fewer passphrase prompts, but also means your key is accessible longer if your computer is compromised.
### Headless/CI Environment Configuration
For CI/CD pipelines or automated scripts where no TTY is available, you need special configuration:
# In gpg-agent.conf, enable loopback pinentry
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
# Then use loopback mode when signing
echo "test" | gpg --pinentry-mode loopback --clearsignFor CI environments, consider:
1. Using a GPG key without a passphrase (less secure, CI-only key)
2. Pre-loading the passphrase via environment variable:
# Using gpg-preset-passphrase (must be enabled in gpg-agent.conf)
echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
# Get the keygrip
gpg --list-secret-keys --with-keygrip
# Preset the passphrase
/usr/lib/gnupg/gpg-preset-passphrase --preset KEYGRIP_HERE <<< "$GPG_PASSPHRASE"### SSH Session Issues
When SSHing to a remote server, GPG pinentry may fail because there's no GUI:
# On the remote server, ensure TTY-based pinentry
echo "pinentry-program /usr/bin/pinentry-tty" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
# Also ensure GPG_TTY is set
export GPG_TTY=$(tty)### Using SSH Keys for Signing Instead of GPG
Git 2.34+ supports signing commits with SSH keys, which is simpler than GPG:
# Configure Git to use SSH signing
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
# Sign commits with SSH
git commit -S -m "Signed with SSH"GitHub, GitLab, and others now support SSH signature verification.
### Debugging GPG Issues
# Test GPG signing with verbose output
GPG_TTY=$(tty) gpg -v --sign test.txt
# Check GPG agent status
gpg-connect-agent 'keyinfo --list' /bye
# View agent log
gpgconf --list-dirs | grep log### Multiple GPG Keys
If you have multiple keys, ensure Git uses the correct one:
# List all keys
gpg --list-secret-keys --keyid-format=long
# Set signing key for specific repository
cd /path/to/repo
git config user.signingkey CORRECT_KEY_ID
# Or set globally
git config --global user.signingkey CORRECT_KEY_ID### Key Passphrase Change
If you recently changed your GPG key passphrase:
# Clear all cached passphrases
gpgconf --kill gpg-agent
# Clear macOS Keychain entries (if applicable)
# Then re-enter the new passphrase
echo "test" | gpg --clearsign### WSL (Windows Subsystem for Linux) Specific Issues
On WSL, you may need to configure pinentry specially:
# Install pinentry-curses
sudo apt install pinentry-curses
# Configure for WSL
echo "pinentry-program /usr/bin/pinentry-curses" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agentAlternatively, use Windows' GPG through WSL interop.
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git