A no-shared-cipher error sounds like one setting to change, and the setting most people change is the wrong one. OpenVPN keeps separate policies for the control channel that performs the TLS handshake and for the data channel that carries packets inside the tunnel, and the error names the first while people edit the second. Comparing what each peer permits, in the right order, turns the guesswork into two or three decisions: version, then suite list, then credentials.

Get that order wrong and you can spend an hour adding an AES name to a list that was never consulted.

Two Cipher Lists, and Only One Breaks the Handshake

The control channel negotiates a TLS session, and its policy is written with tls-cipher for TLS 1.2 and tls-ciphersuites for TLS 1.3. The data channel is configured separately with data-ciphers, where a mismatch produces a connection that establishes and then cannot pass traffic. Both produce errors that mention ciphers, which is why they get confused. A handshake that never completes points at the control channel, while an established tunnel that drops packets points at the data channel.

Read the whole message instead of the first line. A version mismatch, a missing suite, a certificate signature algorithm the peer rejects and a hostname verification failure all end in a TLS error, and only one of them is about your suite list. Keeping those categories apart is most of the diagnosis.

Compare Versions Before You Compare Suites

A peer limited to TLS 1.2 and a peer that requires 1.3 share no version, and no cipher string bridges that. Record tls-version-min and tls-version-max on both sides, or the defaults of the builds in use, since a distribution's OpenSSL policy can raise the floor without any OpenVPN option saying so. If one side is an appliance or a third-party client, its window is whatever its firmware allows. Only once the windows overlap does a suite comparison mean anything.

Those records should also name the actual binaries. A command-line openvpn on your laptop is not necessarily the client that handles an imported profile.

TLS 1.2 and TLS 1.3 Lists Do Not Mix

TLS 1.2 suite names look like ECDHE-RSA-AES256-GCM-SHA384 and belong in tls-cipher, which takes an OpenSSL cipher string. TLS 1.3 suites are named like TLS_AES_256_GCM_SHA384 and belong in tls-ciphersuites; adding one to the 1.2 string does not configure the 1.3 list, and the parser may accept the text without ever matching it. A filter that is correct for one version says nothing about the other. Write down which version each list is meant for.

openvpn --show-tls prints what the local build supports, and that is an inventory rather than a promise: the remote peer may not permit those suites, and the active profile may not enable them. Use it to rule out a build that cannot offer a suite at all, then compare the configured lists.

Prove the Negotiation on a Fresh Connection

A successful handshake is the only evidence that counts, and it has to come from the real client with the real profile. Raise the server's verbosity, connect once, and read the negotiated protocol version and suite from the log instead of assuming the first offered value won. Then confirm the data channel separately with traffic through the tunnel, because a working handshake and a failing data channel are different repairs. Repeat after any configuration change, since a stale client profile is a common false negative.

If no approved common configuration exists, the answer is an upgrade or a migration plan, not a weakened policy. Lowering tls-version-min, disabling verification, or enabling every legacy suite removes the rejection without meeting the security requirement that produced it.

Record the negotiated version, the suite and the data cipher in the change ticket. The next person to meet a TLS error will start from that record instead of from a cipher string found in a forum post.

Ebitabo ebifaananyi