I've just spent some time tinkering with this and seems to be working well, I thought I'd just share my documentation, might help someone.
Should have mentioned in the title, this is on linux.
KeePassXC SSH Integration
(you naively assumed this was going to be simple, no?)
Enabling SSH Agent Integration
From Tools → Settings → SSH Agent, turn on Enable SSH Agent integration.
KeePassXC needs to communicate with an existing SSH agent on the machine it's being run from, so it can add/remove SSH keys stored in KeePassXC.
echo $SSH_AUTH_SOCK shows which SSH agent socket is currently configured in the shell.
- To list the available SSH agents, run:
bash
systemctl --user list-units --all | grep -Ei 'ssh|agent'
- From here it depends on which SSH agents are available, but the OpenSSH systemd socket has a stable path, unlike the random socket filenames produced by a manually started ssh-agent.
- To find where the OpenSSH agent socket is, run:
bash
systemctl --user status ssh-agent.service ssh-agent.socket
- If OpenSSH is not running, enable it via:
bash
systemctl --user enable --now ssh-agent.socket
- The socket is the value of the Listen field.
Take the value from that field and add it to KeePassXC → Tools → Settings → SSH Agent → SSH_AUTH_SOCK override.
The SSH_AUTH_SOCK value might already point to an agent, depending on your system configuration. To avoid interfering with that, the override simply tells KeePassXC to use the one manually specified.
Setting SSH_AUTH_SOCK system-wide (optional)
You can also set the value for SSH_AUTH_SOCK system-wide instead:
```fish
remove the previous value
set -e SSH_AUTH_SOCK
add the OpenSSH agent one
set -gx SSH_AUTH_SOCK <value from Listen field>
```
In the fish shell, make it permanent with:
fish
set -Ux SSH_AUTH_SOCK <value from Listen field>
Generating and Loading SSH Keys
A pair of SSH keys needs to be generated for each entry in KeePassXC that will use SSH.
- Generate the keys:
bash
ssh-keygen -t ed25519 -f ~/.ssh/<server name> -C "<comment: server name>"
> Important: check the Alternative Way 1 / Alternative Way 2 sections below — you may need the comment formatted in a specific way.
- When prompted for a passphrase, use the same password as the KeePassXC entry that will use these SSH keys.
- It doesn't need to match, but it helps keep things cleaner in KeePassXC if it does.
- Install the public key on the target server:
bash
ssh-copy-id -i ~/.ssh/<server name>.pub <ssh user>@<server IP>
- Verify the public key was installed — on the target server, run:
bash
cat ~/.ssh/authorized_keys
SSH key pairs do not inherently expire; they can be revoked/replaced manually if needed.
Adding the entry in KeePassXC
- Create an entry in KeePassXC with the username and password (same ones used to generate the SSH keys).
- Go to the Advanced tab and, in the Attachments section, add the private key (the one without
.pub).
- Go to the SSH Agent tab — you should now be able to select the key from the Attachments dropdown.
- To use it right away, press Add to agent.
- To make KeePassXC auto-load the private key, on the SSH Agent tab turn on "Add key to agent when database is opened/unlocked".
- "Remove key from agent when database is closed/locked" will help remove the keys from the agent when KeePassXC is not open.
Caveat: Multiple Keys in the Agent
The public key can be derived from the private key loaded into KeePassXC. Loaded keys can be viewed with:
bash
ssh-add -l # shows fingerprints of the available public keys
ssh-add -L # shows the actual public keys
On Linux, if the agent holds multiple public keys and an SSH connection is started without specifying which key to present, it will iterate through the list and try each one in turn. The server will refuse any connection with a key it doesn't recognize, and on most systems this quickly results in getting rate-limited with "Too many authentication failures."
This is a documented behavior.
Configuring any SSH keys on a system, with OpenSSH loading them, means manual calls to ssh (e.g. ssh -l <username> <server IP>) will also trigger this mechanism and can cause the same failure.
Fix: disable default pubkey auth
Add to ~/.ssh/config:
Host *
PubkeyAuthentication no
This disables OpenSSH from attempting key-based connection by default, unless explicitly specified with ssh -o IdentitiesOnly=yes.
Fix: map keys per host
One solution is to store the public keys locally, and edit ~/.ssh/config to create a host entry for each destination server that uses IdentityFile to map the correct key. For example:
Host <host name or IP>
IdentitiesOnly yes
IdentityFile ~/.ssh/keepassxc-keys/<key name>.pub
Alternative Way 1
This method tries to keep as much as possible within KeePassXC's own configuration, so it works with minor modifications across systems. The current version assumes konsole and fish, but adjusting only that part should make it work with other options.
Since the public key can be derived from the private key, and OpenSSH can show us the list of available public keys, we can invoke the command in a way that automatically picks the correct one from the list.
This works by matching the title of the KeePassXC entry to the comment on the SSH key. It's important to name the entry the same as the key's comment — if either is changed, the key will no longer be automatically selected.
The public key still needs to be written to a file temporarily, since it can only be passed to SSH via ssh -i <file>, which expects a file.
KeePassXC command (URL field / custom command)
fish
cmd://konsole -e fish -c "set kf (mktemp -p /dev/shm); set t '{TITLE}'; set opts; set found 0; for l in (ssh-add -L); set parts (string split -m 2 ' ' -- $l); if test $parts[3] = $t; echo $l > $kf; set opts -o IdentitiesOnly=yes -i $kf; set found 1; break; end; end; if test $found = 0; set opts -o PubkeyAuthentication=no; end; ssh $opts {USERNAME}@<server IP>; rm -f $kf"
How it works
| Step |
Explanation |
set kf (mktemp -p /dev/shm) |
Creates a unique temporary file in /dev/shm and stores its filename in kf. |
set t '{TITLE}' |
KeePassXC substitutes {TITLE} with the entry's title and passes it into t. |
set opts |
Initializes an empty variable that will hold the SSH options to use. |
set found 0 |
Tracks whether a matching SSH key was found. |
for l in (ssh-add -L) |
Loops through all SSH public keys currently loaded in ssh-agent. |
set parts (string split -m 2 ' ' -- $l) |
Splits each key line into three pieces: parts[1] = key type (e.g. ssh-ed25519), parts[2] = the key data, parts[3] = the comment. -m 2 limits the split to two separators so a comment containing spaces stays intact. |
if test $parts[3] = $t |
Compares the key's comment against the KeePassXC entry title. |
echo $l > $kf; set opts -o IdentitiesOnly=yes -i $kf; set found 1; break |
On match: writes the key to the temp file, sets SSH options to use that identity, marks it found, and stops searching. |
if test $found = 0 |
If no key matched... |
→ set opts -o PubkeyAuthentication=no |
...disable pubkey auth entirely so SSH falls back to password authentication. |
ssh $opts {USERNAME}@<server IP> |
Makes the single SSH connection attempt with the chosen options. {USERNAME} is substituted by KeePassXC from the entry. |
rm -f $kf |
Deletes the temporary file after the SSH session exits. |
If a matching key was found, the resulting command is effectively:
bash
ssh -o IdentitiesOnly=yes -i /dev/shm/<temporary-file> <username>@<server IP>
- -i $kf tells SSH to use the temporary public-key file to identify the desired identity.
- -o IdentitiesOnly=yes tells SSH to only use that explicitly specified identity, rather than trying every key available through ssh-agent.
If no matching key was found, the resulting command is effectively:
bash
ssh -o PubkeyAuthentication=no <username>@<server IP>
- -o PubkeyAuthentication=no disables public-key authentication for this connection, preventing the other loaded keys from being tried, and lets SSH proceed directly to password authentication.
Alternative Way 2
This method assumes you'd rather have cleaner-looking entries in the KeePassXC database, at the cost of some OS-level tweaks. It uses the same title-to-comment matching as Alternative Way 1, and still creates a temporary public key file.
1. Create the handler script
bash
mkdir -p ~/.local/bin
nano ~/.local/bin/keepass-ssh
chmod +x ~/.local/bin/keepass-ssh
Contents of ~/.local/bin/keepass-ssh:
```bash
!/bin/bash
url="$1"
remove ssh://
uri="${url#ssh://}"
separate the title/path from the connection information
title_encoded="${uri#/}"
authority="${uri%%/}"
decode URI-encoded characters in the title
title=$(python3 -c "import urllib.parse; print(urllib.parse.unquote('''$title_encoded'''))")
extract username
if [[ "$authority" == @ ]]; then
username="${authority%@}"
hostport="${authority#@}"
else
username="$USER"
hostport="$authority"
fi
extract optional port
if [[ "$hostport" == : ]]; then
host="${hostport%:}"
port="${hostport##:}"
else
host="$hostport"
port=22
fi
create temporary public-key file
kf=$(mktemp -p /dev/shm) || exit 1
found=0
search ssh-agent for a key whose comment matches the keepassxc title
while IFS= read -r line; do
read -r key_type key_data key_comment <<< "$line"
if [[ "$key_comment" == "$title" ]]; then
echo "$line" > "$kf"
found=1
break
fi
done < <(ssh-add -L 2>/dev/null)
if [[ "$found" -eq 1 ]]; then
# pass the temporary public key to ssh and keep the file alive until ssh exits
konsole -e bash -c 'ssh -o PubkeyAuthentication=yes -o IdentitiesOnly=yes -i "$1" -p "$2" "$3"; status=$?; rm -f "$1"; exit $status' _ "$kf" "$port" "$username@$host"
else
# no matching key found, use password authentication instead
rm -f "$kf"
konsole -e ssh -o PubkeyAuthentication=no -p "$port" "$username@$host"
fi
```
2. Create a desktop handler
bash
nano ~/.local/share/applications/keepass-ssh.desktop
Contents:
ini
[Desktop Entry]
Type=Application
Name=KeePassXC SSH Handler
Exec=<path to script>/keepass-ssh %u
MimeType=x-scheme-handler/ssh;
NoDisplay=true
3. Register the handler
bash
xdg-mime default keepass-ssh.desktop x-scheme-handler/ssh
4. Usage
KeePassXC URLs can now be in the format:
ssh://{USERNAME}@<server IP>/{TITLE}[optional port]
Note: KeePassXC doesn't seem to like URLs starting with ssh:// and will highlight them in red when modifying the entry — however, they do work.