# How to Debug Connection Issues When Running testssl.sh

> Troubleshoot testssl.sh connection problems with the --debug flag for file inspection, adjusting MAX_OSSL_FAIL and MAX_SOCKET_FAIL to manage transient errors and get clearer output.

- Repository: [Dirk Wetter/testssl.sh](https://github.com/drwetter/testssl.sh)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Use the `--debug=<1-6>` flag to retain temporary files in `/tmp/testssl.*`, inspect the raw OpenSSL `s_client` output, and adjust `MAX_OSSL_FAIL` or `MAX_SOCKET_FAIL` environment variables to prevent premature aborts during transient failures.**

When [`testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/testssl.sh) fails to establish a TLS connection, the root cause often hides in OpenSSL handshake details or network timeouts. This guide explains how to leverage the built-in debug infrastructure in the [`drwetter/testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/drwetter/testssl.sh) repository to diagnose connection failures by examining temporary files, interpreting failure counters, and using the `debugme` helper function.

## How testssl.sh Handles Connection Failures

Two core components manage connection problems according to the source code.

**`$OPENSSL s_client` invocations** – All TLS handshakes are executed via OpenSSL's `s_client` command (defined around line 36 in [`testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/testssl.sh)). This is the actual mechanism performing network probes and capturing server responses.

**`connectivity_problem` function** – Located at lines 2579-2595, this function tracks failure counts using `NR_OSSL_FAIL` and `NR_SOCKET_FAIL` counters. It aborts execution when reaching `MAX_OSSL_FAIL` (OpenSSL errors) or `MAX_SOCKET_FAIL` (TCP errors) thresholds, printing a fatal error message when limits are exceeded.

## Debug Infrastructure and Flags

### Debug Levels (--debug)

The `--debug=<0-6>` parameter (documented near line 21621) controls verbosity and file retention:

- `0` – No debug output (default)
- `1-2` – Preserves temporary files in `/tmp/` or the current directory for post-run analysis
- `3-6` – Activates verbose internal diagnostics via the `debugme` helper

### The debugme Helper Function

Defined at lines 834-837, `debugme` executes commands only when `DEBUG` is set to 2 or higher. It prints diagnostics to stderr and archives output in the temporary directory, allowing you to see exactly what commands were executed during the scan.

### Temporary Directory Structure

Each execution creates `$TEMPDIR` (default `/tmp/testssl.<PID>`, implemented at line 21658). This directory stores critical intermediate data:

- Raw handshake data: `$TEMPDIR/<host>.s_client.txt`
- Parsed server responses: `$TEMPDIR/<host>.parse_tls_serverhello.txt`
- Error streams: `$ERRFILE`

### Failure Thresholds

Environment variables control abort behavior to prevent infinite loops on broken targets:

- `MAX_OSSL_FAIL` – Maximum OpenSSL handshake failures before fatal exit (default is typically low for fast failure)
- `MAX_SOCKET_FAIL` – Maximum TCP connection failures before fatal exit

When `connectivity_problem` detects threshold breaches, it issues a fatal error suggesting you increase the corresponding limit.

### Special Debug Options

The `-Z` flag forces TLS fallback SCSV testing (referenced at lines 18898-18899). Combined with `--debug=1`, it generates extra log files (`*tls_fallback_scsv.txt`) useful when normal handshakes are rejected by the server.

## Step-by-Step Debugging Workflow

Follow this sequence to isolate connection problems.

1. **Run with debug retention**

   ```bash
   testssl.sh --debug=2 example.com:443
   ```

   Note the `TEMPDIR` path printed in the output summary.

2. **Inspect temporary files**

   ```bash
   cat /tmp/testssl.XXXXXX/example.com.s_client.txt
   ```

3. **Handle OpenSSL-specific failures**

   If you see "openssl s_client connect problem", increase the threshold to bypass transient TLS issues:

   ```bash
   MAX_OSSL_FAIL=20 testssl.sh --debug=1 example.com:443
   ```

4. **Handle TCP-level failures**

   For "TCP connect problem" errors, verify reachability with `telnet` or `nc` first, then adjust:

   ```bash
   MAX_SOCKET_FAIL=15 testssl.sh --debug=1 example.com:443
   ```

5. **Force fallback testing**

   ```bash
   testssl.sh -Z --debug=1 example.com:443
   ```

## Practical Code Examples

### Basic Debug Run with File Retention

```bash

# Retain all temporary files for inspection

testssl.sh --debug=2 example.com:443

```

After completion, examine the directory path printed in the output summary.

### Custom Temporary Directory

```bash
TEMPDIR=$(mktemp -d)
testssl.sh --debug=2 --tempdir "$TEMPDIR" example.com:443

# Inspect raw OpenSSL output

cat "$TEMPDIR/example.com.s_client.txt"

```

### Override Failure Thresholds

```bash

# Allow 15 OpenSSL failures before aborting

MAX_OSSL_FAIL=15 testssl.sh --debug=1 example.com:443

# Allow 10 TCP timeouts

MAX_SOCKET_FAIL=10 testssl.sh --debug=1 example.com:443

```

### Debug TLS Fallback Issues

```bash
testssl.sh -Z --debug=1 example.com:443
cat "$TEMPDIR/example.com.tls_fallback_scsv.txt"

```

## Key Source Files

Understanding these files in the repository helps trace connection logic:

- **[`testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/testssl.sh)** (main script) – Line 36 defines the `$OPENSSL s_client` invocation; line 21658 creates `$TEMPDIR`; line 21621 documents debug flags
- **`debugme` function** – Lines 834-837 implement the conditional execution wrapper that logs commands only when `DEBUG ≥ 2`
- **`connectivity_problem` function** – Lines 2579-2595 contain the failure counting and abort logic for both OpenSSL and socket errors
- **[`utils/resume.sh`](https://github.com/drwetter/testssl.sh/blob/main/utils/resume.sh)** – Helper for session resumption tests using `s_client`
- **[`utils/checkcert.sh`](https://github.com/drwetter/testssl.sh/blob/main/utils/checkcert.sh)** – Extracts certificates via `s_client -showcerts`
- **[`etc/client-simulation.txt`](https://github.com/drwetter/testssl.sh/blob/main/etc/client-simulation.txt)** – Data file used by the client simulation engine; useful when debugging simulated browser handshakes

## Summary

- **Enable debugging** with `--debug=2` to preserve temporary files in `/tmp/testssl.<PID>` for post-scan analysis
- **Inspect raw output** in `$TEMPDIR/<host>.s_client.txt` to see exact OpenSSL error messages and server responses
- **Adjust thresholds** using `MAX_OSSL_FAIL` and `MAX_SOCKET_FAIL` environment variables for flaky networks or slow targets
- **Use `-Z` flag** with `--debug=1` to diagnose TLS fallback SCSV rejection issues
- **Check the `debugme` function** at line 834 to understand how conditional logging wraps sensitive commands

## Frequently Asked Questions

### How do I see the exact OpenSSL error when testssl.sh fails to connect?

Run [`testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/testssl.sh) with `--debug=2` and inspect the `*.s_client.txt` file in the temporary directory printed at the end of the scan. This file contains the raw stderr and stdout from the `$OPENSSL s_client` command that failed, including specific handshake error codes.

### What is the difference between MAX_OSSL_FAIL and MAX_SOCKET_FAIL?

`MAX_OSSL_FAIL` counts failures occurring during the TLS handshake phase (certificate validation errors, protocol version mismatches), while `MAX_SOCKET_FAIL` counts TCP-level connection failures (timeouts, connection refused, network unreachable). Increase the relevant variable based on which error message appears in the `connectivity_problem` output at lines 2579-2595.

### Where are the debug log files stored?

By default, logs are stored in `/tmp/testssl.<PID>/`. When using `--debug=1` or higher, the script prints the exact `TEMPDIR` path at the end of execution. You can also specify a custom location with `--tempdir /path/to/dir` to make files easier to locate.

### Why does testssl.sh abort even with --debug enabled?

The script uses hardcoded failure thresholds in the `connectivity_problem` function. If `NR_OSSL_FAIL` exceeds `MAX_OSSL_FAIL` (or the socket equivalent), it calls `fatal` and exits regardless of debug settings. Override these limits by setting the environment variables (e.g., `MAX_OSSL_FAIL=50`) before invoking the script.