How to Disconnect Hung SSH Session [100% Working]


Written by - Deepak Prasad

In the world of safe online connections, SSH (Secure Shell) is like a strong guard that keeps our information safe. A big part of using SSH well is knowing how to end sessions the right way. This guide will show you different ways and commands, like exit ssh, to properly end your SSH sessions.

In this tutorial, you’ll learn different ways to close SSH connections safely. We will talk about various ways to end a session, like typing specific commands and using keyboard shortcuts. It’s also important to know what to do if an SSH session stops responding. We will show you how to ‘kill’ a stuck SSH session so it won’t be a problem.

But there's more. This guide also has tips and tricks, like how to set up automatic session timeouts and solve common problems related to ending SSH connections. We’ll also show you how to change SSH settings to make it work the way you want.

So, get ready! This guide will teach you everything you need to know to manage, use, and, most importantly, safely close your SSH connections.

 

Methods to Manually Close SSH Connection

Managing SSH connections effectively is crucial in network administration. Knowing how to manually close SSH sessions allows administrators to maintain secure and efficient systems. Here’s a breakdown of various methods to manually close an SSH connection:

 

1. Using ‘exit’ Command

  • The exit command is a straightforward way to close the SSH connection. Typing exit in the terminal will terminate the session, disconnecting you from the remote host.
  • Example: Simply type exit in the terminal and press Enter.
exit

 

2. Using Keyboard Shortcuts

  • You can also use keyboard shortcuts to end SSH sessions quickly. A common shortcut is Ctrl+D. This action sends an EOF (End Of File) marker, closing the connection.
  • Example: While in the terminal, press Ctrl+D to close the SSH connection.

 

3. Closing the Terminal Window

  • Sometimes, you might choose to close the SSH connection by simply closing the terminal window. This method will also terminate the SSH session.
  • Example: Click the close button on the terminal window, or you can use a shortcut such as Alt+F4 (on most systems) to close the window.

 

4. Using Escape Characters Sequence

Another method to end an SSH session is by using a sequence of escape characters. This method is particularly helpful if the standard ways, like the exit ssh command or closing the terminal window, are not applicable or if you're facing issues with the regular approaches.

  • First, press <Enter> to make sure that nothing precedes the escape character.
  • Next, press <shift> + <tilde> (~). This combination serves as the escape character in SSH.
  • Finally, press the <period> (.) key. This sequence effectively closes the SSH connection.

So, the complete sequence will look like this: <Enter> <shift>+<tilde> <period>

 

Automating exit SSH with Session Timeout

Ensuring that SSH connections remain secure is paramount, and one effective strategy to bolster security is by automating SSH session timeouts. By doing this, you facilitate automatic logouts, effectively causing the SSH session to "exit ssh" after a predefined period of inactivity, which is crucial for preventing unauthorized access.

 

1. Server-Side Parameters (TCPKeepAlive, ClientAliveInterval, and ClientAliveCountMax)

These settings in the SSH daemon configuration file (/etc/ssh/sshd_config) define how the server manages idle connections.

  • Usage:
    • TCPKeepAlive: Determines whether the system will send keepalive messages to the other side. If they are not responded to, the connection will be terminated.
    • ClientAliveInterval: Sets a timeout interval for client responses.
    • ClientAliveCountMax: Determines how many client alive messages can be unresponded before the server disconnects the client.
TCPKeepAlive yes
ClientAliveInterval 300
ClientAliveCountMax 2

The TCPKeepAlive yes setting ensures that the server sends TCP keepalive messages to check the vitality of the connection. Coupled with this, the ClientAliveInterval 300 means that the server will wait for 300 seconds before sending a null packet to the client to solicit a response, ensuring that the client is still active and responsive. This process is allowed to repeat 2 times as per ClientAliveCountMax 2, without a response from the client, before the server decides to terminate the connection.

 

2. Client-Side Parameters (ServerAliveInterval and ServerAliveCountMax)

These settings in the SSH client configuration file (~/.ssh/config) control how the client responds to server timeouts.

  • Usage:
    • ServerAliveInterval: Configures the client to send keepalive messages to the server.
    • ServerAliveCountMax: Specifies how many keepalive messages can be sent without receiving a response before disconnecting.
Host *
  ServerAliveInterval 300
  ServerAliveCountMax 2

This means that the SSH client will send a null packet to the server every 300 seconds (5 minutes) to keep the connection alive, and it will do this a maximum of 2 times without receiving a response back from the server before it decides to close the SSH connection.

 

When and Where to Use Server or Client Parameters

  • Server Parameters: Useful when you want to control the sessions from the server’s end, enforcing a policy for all clients connecting to the server.
  • Client Parameters: Beneficial for clients wanting to maintain their connection policies, irrespective of the server settings.

 

Conditions Where These Might Not Work

  • Network Instability: Unreliable networks might disrupt the keepalive messages, causing premature disconnections.
  • Firewall Configurations: Certain firewall rules might block keepalive messages, rendering the settings ineffective.
  • Mismatched Configuration: Misaligned settings between client and server configurations might lead to unexpected disconnection behaviors.

 

Handling Stuck or Unresponsive SSH Sessions

When working with SSH connections, encountering frozen or unresponsive sessions can be a common issue. However, this can be managed and rectified using various approaches, ensuring that you maintain the reliability and integrity of your SSH connections.

1. Utilizing Escape Characters:

Escape characters are a powerful tool to manage SSH sessions. If a session becomes unresponsive, you can use a sequence of escape characters to terminate the connection manually. For instance, you can use the <Enter>, <~>, and <.> sequence. First, you hit <Enter> to ensure no other character precedes the escape character, then <~> as the escape character, followed by <.> to terminate the connection. This approach is effective as it allows you to exit SSH sessions that have become stuck directly, restoring control over the terminal.

2. Employing the 'kill' Command:

Another method to manage frozen SSH sessions is by employing the 'kill' command. If you find that a particular SSH session is not responsive, you can open another terminal window, identify the process ID (PID) of the SSH session, and then use the 'kill' command to terminate it. For instance:

Use the ps command to identify the PID of the SSH session:

ps aux | grep ssh

After identifying the PID, use the 'kill' command:

kill -9 [PID]

In this method, you forcibly terminate the unresponsive SSH session, ensuring that resources are not unnecessarily consumed by stagnant connections.

 

Using timeout to Kill Stuck SSH Sessions

timeout is a useful command in Unix-like operating systems that allows users to execute a command with a time limit. When applied to SSH sessions, it can automatically terminate sessions after a specified duration, ensuring that sessions don’t linger indefinitely if left unattended. This approach can be particularly useful in maintaining operational efficiency and security.

Here’s how you can use the timeout command to manage SSH sessions:

1. Applying timeout to SSH Sessions:

You can prefix the SSH command with timeout followed by the desired time limit to establish a session with a pre-set duration.

timeout 300 ssh username@hostname

In this example, the SSH session will automatically terminate after 300 seconds (5 minutes), whether it’s active or idle.

2. Utilizing timeout for Specific Commands within SSH:

You can also use timeout to execute specific commands within an SSH session for a limited period.

ssh username@hostname "timeout 300 command_to_execute"

Here, the specified command within the SSH session will run for a maximum of 300 seconds before it’s automatically terminated.

3. Combining timeout with Script Execution:

If you’re running a script over SSH, you can apply the timeout command to limit the execution time of the script.

timeout 300 ssh username@hostname 'bash -s' < script.sh

The script (script.sh) will execute on the remote server but will be terminated if it runs longer than 300 seconds.

 

Identify and Disconnect Hung SSH Sessions

Detecting if an SSH session is truly "hung" can be a bit complex and might depend on various factors, such as network issues, server responsiveness, or specific user activity.

In my case I had a situation where due to performance overload, some of the SSH sessions were getting infinitely stuck and they were not getting cleaned up on the server side. So I wrote this Python script which looks out for all such SSHD processes and if found then I just restart SSHD service as this was a container and I didn't have privilege to kill hung sessions.

The scripts basically greps all sessions with sshd.*[priv] regex as the SSH connections where performed using SSH keys. Later if I find any such process which are also "Sleeping" then I assume them as hung and plan to kill them with a service restart.

def find_sshd_priv_and_restart():
    log.info("Starting check for sleeping SSHD processes.")
    
    try:
        process = subprocess.Popen(['ps', '-ef'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        grep_process = subprocess.Popen(['grep', 'sshd.*\\[priv\\]'], stdin=process.stdout, stdout=subprocess.PIPE)
        process.stdout.close()

        stdout, _ = grep_process.communicate()
        text = stdout.decode()

        num_processes = len(text.strip().split('\n')) if text.strip() else 0
        if num_processes == 0:
            log.info("No sleeping SSHD processes found.")
            return

        log.info(f"Found {num_processes} sleeping SSHD processes.")
        pattern = re.compile(r'\S+\s+(\d+)')
        matches = pattern.findall(text)

        for match in matches:
            pid = match
            log.info(f"Checking PID: {pid}")

            process_cmdline = subprocess.Popen(['ps', '-p', pid, '-o', 'args='], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout, _ = process_cmdline.communicate()
            full_cmdline = stdout.decode().strip()
            log.info(f"The command name for PID {pid}: {full_cmdline}")

            process = subprocess.Popen(['ps', '-p', pid, '-o', 'stat='], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout, _ = process.communicate()
            status = stdout.decode().strip()
            log.info(f"Process {pid} has status: {status}")

            if 'S' in status:
                log.info(f"Process {pid} is sleeping. Attempting to restart sshd.")
                
                # Restart sshd and check if the restart was successful
                restart_result = subprocess.run(['supervisorctl', 'restart', 'sshd'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                if restart_result.returncode != 0:
                    log.error("Failed to restart sshd.")
                    return

                # Sleep for 2 seconds to allow for the restart to take effect
                time.sleep(2)

                
                # Verify that sshd is running
                status_check = subprocess.Popen(['supervisorctl', 'status', 'sshd'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdout, _ = status_check.communicate()
                if 'RUNNING' not in stdout.decode():
                    log.error("sshd is not running after attempted restart.")
                else:
                    log.info("sshd restarted successfully.")
                
                return

    except Exception as e:
        log.error(f"An error occurred: {e}")

Here is another shell script which checks all the connected SSH sessions and if any of the session is Sleeping for more than 30 minutes then it considers them as hung SSH session and kills them:

#!/bin/bash

# Set the idle time limit (in minutes) to consider the session as hung
IDLE_LIMIT=30

# Function to kill a process by PID
kill_process() {
    kill -9 $1
    echo "Killed SSH session with PID $1"
}

# Get a list of users, idle times, and PIDs
idle_sessions=$(w -h | awk '{print $1,$2,$5}')

# Loop over each user, tty, and idle time
while read -r user tty idle; do
    # Remove any special characters from the idle time
    idle_clean=${idle//[^0-9]/}
    
    # Check if the idle time exceeds the limit
    if (( idle_clean >= IDLE_LIMIT )); then
        # Get the state of the SSH session
        state=$(ps -o state= -t $tty | tr -d ' ')
        
        # Check if the state is sleeping (S)
        if [[ $state == "S" ]]; then
            # Get the PID of the SSH session
            pid=$(ps -o pid= -t $tty | tr -d ' ')
            
            # Kill the SSH session
            kill_process $pid
        fi
    fi
done <<< "$idle_sessions"

 

Use Multiplexing with SSH for managing multiple connections

Multiplexing is a powerful feature in SSH that allows a user to establish a single SSH connection and reuse it for multiple SSH sessions. This can optimize the SSH connections by reducing the overhead of creating a new connection every time. It’s highly useful in scenarios where you need to manage multiple SSH connections to a server.

Here’s a step-by-step guide with an example to demonstrate SSH multiplexing:

1. Setting up ControlMaster in SSH Config

Edit the SSH configuration file, generally located at ~/.ssh/config, and add the following configurations:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/multiplex/%r@%h:%p
    ControlPersist 1h

These settings will enable multiplexing for SSH connections and keep the master connection alive for one hour (ControlPersist 1h).

2. Creating the Master Connection

Establish the first SSH connection. This will act as the master connection.

ssh user@example.com

3. Reusing the Master Connection

Open a new terminal window, and SSH to the same host. This will reuse the existing master connection.

ssh user@example.com

4. Closing the Connections

  • Closing the secondary connections won’t affect the master connection.
  • The master connection will remain alive for the duration specified in ControlPersist.

Here is a practical example of executing commands using a multiplexed SSH connection:

Open a terminal and SSH into a server:

ssh user@example.com

Open a new terminal window and execute a command without creating a new connection:

ssh user@example.com ls /var/www

This will execute the ls /var/www command on the server, reusing the existing SSH master connection.

Multiplexing with SSH is an advanced technique that can enhance the efficiency and speed of managing multiple connections to the same host. By reusing a single connection, you avoid the overhead and delay of establishing a new connection for every session, which can be particularly advantageous in network scenarios where you frequently execute commands or manage services remotely.

 

Frequently Asked Questions

How do I close an SSH connection?

Closing an SSH connection can be done in various ways such as typing exit or logout at the prompt and pressing enter, or using the shortcut Ctrl+D. Another way is to simply close the terminal window where the SSH session is running.

What happens if I just close the terminal without properly exiting the SSH session?

If you close the terminal without properly exiting, the SSH session will be terminated abruptly. However, the processes running in the background on the server will continue to run.

How can I automatically close idle SSH connections?

Automatic closure of idle SSH connections can be managed through configurations on both the server and client sides. Parameters like ClientAliveInterval and ClientAliveCountMax on the server, and ServerAliveInterval and ServerAliveCountMax on the client, can be set in the SSH configuration to manage idle connections.

What does ClientAliveInterval and ServerAliveInterval mean in SSH configurations?

ClientAliveInterval is a server-side configuration that specifies the time in seconds that the server will wait before sending a null packet to the client to keep the connection alive. ServerAliveInterval is a client-side configuration that determines the frequency of sending keepalive messages to the server.

How can I manage multiple SSH connections efficiently?

Managing multiple SSH connections can be optimized using SSH multiplexing. This allows the reuse of an existing SSH connection, reducing the overhead of creating a new connection for each session.

How do I kill a frozen or unresponsive SSH session?

Frozen or unresponsive SSH sessions can be managed by using escape characters like ~. or employing commands like kill to terminate the unresponsive sessions based on their Process IDs (PIDs).

What are escape characters, and how are they used in SSH?

Escape characters in SSH, such as ~., are used to control SSH sessions. They allow users to terminate connections, cancel port forwardings, and perform other session-related operations.

 

Summary

Navigating through the intricacies of SSH (Secure Shell) connections can be a nuanced journey. This tutorial has been an expedition through various landscapes of managing, utilizing, and, most importantly, closing SSH connections securely and efficiently. Here are the key takeaways:

  • Exiting SSH Sessions: Exiting or closing SSH connections can be as simple as typing exit at the command prompt or utilizing shortcuts like Ctrl+D. This allows you to gracefully disconnect from SSH, ensuring that the sessions are closed properly.
  • Handling Unresponsive Sessions: At times, SSH sessions might become unresponsive or stuck. Learning how to manage such scenarios, either by using escape characters or employing specific commands, is vital for maintaining system integrity and operational continuity.
  • Automating Session Timeouts: Configuration parameters like ClientAliveInterval and ServerAliveInterval play crucial roles in managing session lifetimes, aiding in automating timeouts, and ensuring that idle sessions do not linger indefinitely, thus helping to exit stuck SSH sessions.Multiplexing for Efficient Connection Management: Multiplexing in SSH is a powerful tool that allows for the management of multiple SSH sessions through a single connection, fostering efficiency, reducing overhead, and optimizing connection management processes.
  • Understanding Advanced Configurations: Delving deeper into SSH configurations enhances the ability to manage sessions better. Understanding directives like TCPKeepAlive, and ClientAliveCountMax gives you better control and customization capabilities over SSH sessions.
  • Strategies for Closing SSH Sessions: Strategies like manual termination, automation of session timeouts, and handling of frozen sessions are critical. They ensure that you can not only establish but also close SSH connections securely and efficiently.

Below are some official documentation and reputable resources where you can explore more about SSH connections and their management:

  1. Official OpenSSH documentation is a comprehensive resource: OpenSSH Documentation
  2. OpenBSD man pages for SSH
  3. RFC 4251 - The Secure Shell (SSH) Protocol Architecture
    • Explore the foundational architecture of SSH: RFC 4251
  4. Various guides and articles related to SSH: SSH.com Resources
  5. Ubuntu’s community documentation on SSH: Ubuntu SSH

 

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can reach out to him on his LinkedIn profile or join on Facebook page.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

4 thoughts on “How to Disconnect Hung SSH Session [100% Working]”

  1. Superb!

    the only article I found on google (not internet, but google 🙂 )
    which correctly describes how to kill a very long SSH session by setting/defining hard limits.

    Reply
  2. I’ve been in this business for quite a while and have always been annoyed about not knowing how to kill only one nested ssh session and not the whole chain. I’m happy I ran across your page!

    Reply
  3. This is a great. I was always annoyed with hung ssh sessions and had to kill them using ps -a, kill and other tricks. This article explains the solution perfectly and I am saved from performing so many not so comfortable actions just in order to get rid of a hung ssh session.

    Reply
  4. This article is worthy of recognition and comment. I found this material attention-grabbing and engrossing. This is well-scripted and highly informative.

    Reply

Leave a Comment

X