Kick One OpenVPN Client: Kill, Deny or Revoke a Cert?
Three OpenVPN actions remove a client, but each ends something different: a live session, one login attempt, or the right to reconnect. Pick by identity.
You have a common name and an address in your notes, and three commands that all look like they remove a client. Only one of them does what you want, and the choice depends on whether you need to end the session that is running now, refuse the next login, or take away the right to connect at all. Read the identity you actually hold before you touch anything, because an OpenVPN pool hands the same tunnel address to a different session later.
Which identity you actually have
A version 3 status file is the usual starting point. The CLIENT_LIST section carries the common name, the real address, byte counters and connection time; the ROUTING TABLE section maps a virtual address to a common name with a last-reference timestamp. The common name is the stable identity. The virtual address is an assignment, and the real address behind a NAT can change between sessions without anything on the server changing.
The management interface exposes a similar view through its status command and adds a client ID per session. That ID is what client-kill expects, and it is not the tunnel address. If you need to know which common name received which address at connect time, the environment of a client-connect script has both, along with the trusted outer address, but that script runs as the OpenVPN user and needs a writable log path.
| What you hold | Where it came from | What it can act on |
|---|---|---|
| Common name | CLIENT_LIST, or the auth hook | kill, and credential revocation |
| Client ID | status on the management socket | client-kill, that one session |
| Tunnel address | ROUTING TABLE, client-connect environment | Nothing durable, the address is recycled |
Kill now, deny at login, revoke for good
Both removal commands in the management interface are session actions. kill takes a common name or a real address and port; client-kill takes the client ID and ends that instance immediately. Neither is a block: a killed client with a valid certificate and password reconnects in seconds, which is fine when you are recycling a test peer and useless when a laptop was stolen.
client-deny is a different kind of decision. It is normally issued from an authentication or client-connect hook and rejects the session with a reason, so it fits a policy that refuses a login rather than one that interrupts a connection. The documentation also warns that a deny issued during a TLS renegotiation invalidates the renegotiated key while the existing session can run until the transition window closes. If the requirement is that the client is gone now, the documented answer is client-kill.
Durable removal lives below all of this. Revoke the certificate and make sure crl-verify points at a list the server actually reloads, disable the client-specific configuration file in the ccd directory, or disable the account in whatever backend the authentication hook queries. A revocation is not instant either: with default reneg-sec settings an established session can keep running until it renegotiates, so the session action and the credential action are complements, not alternatives.
Is the management socket free?
The management interface serves one client at a time. If a GUI or monitoring daemon already holds the connection, your script cannot attach beside it, and depending on the client you may evict the existing one rather than fail cleanly. Its password travels in clear text on that socket, so it belongs on a local address or a unix socket, never on a public interface.
When you cannot take the socket, you still have options, and they are all slower. Drop the GUI's session first if you control it, or accept the credential-layer route and wait for the next renegotiation. What you should not do is restart the service to shed one client, because that ends every other session too and destroys the status file evidence for this one.
The sequence I run on a live server
Attach, read the current state, act on the ID you just read, then read it again. Values copied from a document are the most common way to kill the wrong person.
status # note the client ID and common name
client-kill 3 # end that session now
kill Test-Client # alternative: by common name
status # confirm the session is goneThe name and the number above are placeholders, and IDs are reused after other clients disconnect. Confirm the row is absent before you write anything down as done, and check that the count of connected clients moved by one rather than several.
Confirm it stayed away
Record the common name, the tunnel address, the outer address and the minute of removal. If the same common name appears again a minute later, the session action worked and the credential layer did not, which is a completely different repair from a command that never took effect.
Then test from the client side. A revoked certificate should fail the next handshake; if it still connects, the CRL is not being read at all, and that is the finding worth reporting. Pick the action by what you need to end, confirm with a second status, and fix the credential layer when the answer has to last longer than the session.