How to Set Linux SSH Login Timeout with Shell Scripting

Secure Shell (SSH) access is fundamental to remote server administration, making its security and performance settings critical for IT professionals and managed service providers (MSPs). One frequently overlooked configuration is learning how to set Linux SSH login timeout with Shell scripting, controlled by the LoginGraceTime directive. This setting determines how long a server will wait for a user to successfully authenticate before terminating the session. Automating the configuration of this parameter using a shell script ensures consistency, saves time, and helps enforce security best practices across infrastructure.

Background

The LoginGraceTime directive in the sshd_config file controls the window of time SSH servers allow unauthenticated connections to remain open. The default is usually 120 seconds—ample time for a user to log in, but unnecessarily long in environments where tight security policies are enforced.

For IT administrators managing fleets of Linux machines, especially via RMM platforms like NinjaOne, manually updating sshd_config on each system is not scalable. Automating this with a shell script offers not just convenience but also version control, consistency, and error reduction. This is where the featured script comes in.

The Script

#!/usr/bin/env bash

# Description: Sets the SSH login timeout via LoginGraceTime.
# By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
# Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
# Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
# Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
# Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
# Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
# Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
# EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#
# Preset Parameter: --setTimeoutInSeconds "ReplaceMeWithANumber"
#   The server disconnects after this time if the user has not successfully logged in. If the value is 0, there is no time limit. The default is 120 seconds.
#
# Links: https://man.openbsd.org/sshd_config#LoginGraceTime

# Logs an error message and exits with the specified exit code
die() {
    local _ret="${2:-1}"
    echo "$1" >&2
    exit "${_ret}"
}

_sshd_config="/etc/ssh/sshd_config"

backup_file() {
    file_source=$1
    file_backup="${file_source}_$(date +%Y-%m-%d_%H-%M-%S).backup"
    if [[ -f "${file_source}" ]]; then
        echo "[Info] Backing up $file_source to $file_backup"
        cp "${file_source}" "${file_backup}"
    fi

    # Remove the oldest backup file if there are more than 3 backups

    # Get the list of backup files
    echo "[Info] Finding backup files..."
    _sshd_config_dir=$(dirname "${_sshd_config}")
    _sshd_config_file=$(basename "${_sshd_config}")
    backup_files=$(find "$_sshd_config_dir" -name "${_sshd_config_file}_*.backup" -printf '%T+ %p\n' 2>/dev/null | sort -r | tail -n +4 | cut -d' ' -f2-)
    # Loop through each backup file and remove it
    for backup_file in $backup_files; do
        echo "[Info] Removing $backup_file"
        rm -f "$backup_file"
    done
}

# Check that we are running as root
if [[ $EUID -ne 0 ]]; then
    die "[Error] This script must be run as root." 1
fi

if [[ -z "${setTimeoutInSeconds}" ]]; then
    die "[Error] Timeout was not specified." 1
fi

# Remove any leading zeros
setTimeoutInSeconds=$((setTimeoutInSeconds))

if ((setTimeoutInSeconds > 86400)); then
    die "[Error] Timeout can not be greater than 86400." 1
fi

if ((setTimeoutInSeconds < 0)); then
    die "[Error] Timeout can not be less than 0." 1
fi

_should_reload="false"

# Default is 0; which is disabled
_loginGraceTime="LoginGraceTime ${setTimeoutInSeconds}"

# Check if the sshd_config file exists
if [[ -f "${_sshd_config}" ]]; then
    # Check if the LoginGraceTime option is already set to _loginGraceTime
    if grep -q "^${_loginGraceTime}" "${_sshd_config}"; then
        echo "[Info] Timeout is already set to ${setTimeoutInSeconds}."
        _should_reload="false"
    elif grep -q "^LoginGraceTime .*" "${_sshd_config}"; then
        backup_file "${_sshd_config}"
        # First check if the option is not commented out and set to yes
        # Then set the LoginGraceTime option to ${setTimeoutInSeconds}
        sed -i "s/^LoginGraceTime.*/${_loginGraceTime}/" "${_sshd_config}"
        echo "[Info] LoginGraceTime set to ${setTimeoutInSeconds}."
        _should_reload="true"
    elif grep -q "^#LoginGraceTime" "${_sshd_config}"; then
        backup_file "${_sshd_config}"
        # First check if the option is commented out
        # Then set the LoginGraceTime option to ${setTimeoutInSeconds}
        sed -i "s/^#LoginGraceTime.*/${_loginGraceTime}/" "${_sshd_config}"
        echo "[Info] LoginGraceTime set to ${setTimeoutInSeconds}, as it was commented out."
        _should_reload="true"
    else
        backup_file "${_sshd_config}"
        # Append the LoginGraceTime option to the end of the sshd_config file
        # If the past checks have not found the option, appending it will ensure that it is set to no
        echo "${_loginGraceTime}" >>"${_sshd_config}"
        echo "[Info] LoginGraceTime set to ${setTimeoutInSeconds} at the end of the sshd_config file."
        _should_reload="true"
    fi

    # Check that this system is running systemd-based
    _type=$(
        # Get the type of init system
        file /sbin/init 2>/dev/null | awk -F/ '{print $NF}' 2>/dev/null
    )
    if [[ "${_type}" == "systemd" ]] && [ "$(command -v systemctl)" ]; then
        echo "[Info] Reloading ${sshd_service} service..."
        # Find the sshd service
        sshd_service=$(
            # Get the ssh service, if two are found use the first one. Likely the first one is a symlink to the actual service file.
            systemctl list-unit-files | grep -E "^(sshd|ssh|openssh-server)\.service" | awk -F' ' '{print $1}' | head -n 1
        )
        if [[ -z "${sshd_service}" ]]; then
            die "[Error] sshd service is not available. Please install it and try again." 1
        fi
        # Check that ssh service is enabled
        if systemctl is-enabled "${sshd_service}" >/dev/null; then
            echo "[Info] ${sshd_service} is enabled."
        else
            die "[Info] ${sshd_service} is not enabled. When enabled and started, PermitEmptyPasswords will be set to no." 0
        fi
        # Check that ssh service is running
        if systemctl is-active "${sshd_service}" >/dev/null; then
            echo "[Info] ${sshd_service} is running."
            if [[ "${_should_reload}" == "true" ]]; then
                # Reload sshd.service
                if systemctl reload "${sshd_service}"; then
                    echo "[Info] sshd service configuration reloaded."
                else
                    die "[Error] Failed to reload ${sshd_service}. Please try again." 1
                fi
            else
                echo "[Info] sshd service configuration will not be reloaded as there is no need to do so."
            fi
        else
            echo "[Info] ${sshd_service} is not running."
        fi
    else
        echo "[Info] Restarting sshd service..."
        # Check that the service command is available
        if ! [ "$(command -v service)" ]; then
            die "[Error] The service command is not available. Is this an initd type system (e.g. SysV)? Please try again." 1
        fi
        # Find the sshd service
        sshd_service=$(
            # Get the list of services
            service --status-all | awk -F' ' '{print $NF}' | grep sshd
        )
        if [[ -z "${sshd_service}" ]]; then
            die "[Error] sshd service is not available. Please install it and try again." 1
        fi
        if [[ "${_should_reload}" == "true" ]]; then
            # Restart sshd service
            if service "${sshd_service}" restart; then
                echo "[Info] sshd service restarted."
            else
                die "[Error] Failed to restart sshd service. Please try again." 1
            fi
        else
            echo "[Info] sshd service configuration will not be restarted as there is no need to do so."
        fi
    fi
else
    die "[Error] The sshd_config file does not exist." 1
fi

 

Detailed Breakdown

The provided shell script automates the process of setting the SSH login timeout on a Linux system by modifying the LoginGraceTime directive in /etc/ssh/sshd_config. Here’s a step-by-step breakdown of its operation:

  1. Input Validation
    The script expects a preset parameter –setTimeoutInSeconds. It ensures:

    • The user running the script is root.
    • The timeout value is within a valid range (0 to 86400 seconds).
  2. Backup Handling
    Before any modification:

    • The script backs up the current sshd_config file with a timestamped suffix.
    • It retains the three most recent backups, deleting older ones to avoid clutter.
  3. Configuration Logic
    The script intelligently updates the LoginGraceTime directive:

    • If already set correctly, it exits early.
    • If present but incorrect, or commented out, it updates the line.
    • If missing, it appends the new setting to the end of the file.
  4. Service Reload/Restart
    Based on the init system:

    • On systemd-based systems: uses systemctl reload for efficiency.
    • On SysV/init.d systems: falls back to service sshd restart.
  5. Error Handling
    The script includes robust checks and user-friendly messages to alert administrators of issues, such as missing sshd_config or SSH services not running.

Potential Use Cases

Case Study

An MSP manages 500 Linux servers for a client with strict compliance requirements. The client mandates that SSH sessions terminate if authentication isn’t completed within 30 seconds. Using NinjaOne’s custom scripting capabilities, the MSP deploys this script with the parameter –setTimeoutInSeconds 30 across the entire infrastructure. The script runs silently, backs up configurations, enforces the policy, and restarts services as needed—saving hours of manual work and ensuring compliance.

Comparisons

There are alternative ways to set LoginGraceTime, such as:

  • Manual Editing
    Logging into each machine and editing /etc/ssh/sshd_config using vim or nano. This is time-consuming and error-prone.
  • Ansible or Puppet Modules
    While powerful, these tools require significant setup and are overkill for simple changes on small to mid-sized networks.
  • Shell Script Automation (this script)
    Lightweight, portable, and easy to integrate into RMM platforms. It balances simplicity with robustness.

FAQs

Q: What happens if sshd_config doesn’t exist?

The script will exit with an error message, ensuring no operations continue.

Q: Can I set the timeout to 0 for no limit?

Yes. Setting –setTimeoutInSeconds 0 removes the timeout, though it’s not recommended for security reasons.

Q: What if the SSH service isn’t enabled or running?

The script will alert you and halt if necessary services aren’t in place.

Q: How do I run this with NinjaOne?

Set the parameter via NinjaOne’s custom script interface, passing –setTimeoutInSeconds 60 as an example.

Implications

Automating SSH login timeout configuration reduces the window for brute-force or unauthorized access attempts. By ensuring consistent timeout policies, organizations minimize idle open sessions—an often exploited vector in attacks. This also ensures compliance with industry standards like CIS Benchmarks and internal security policies.

Moreover, regular backups maintained by the script make it safer to deploy changes without fear of irreversible errors.

Recommendations

  • Always test on a non-production machine before widespread deployment.
  • Use conservative timeout values (e.g., 30–60 seconds) that balance usability with security.
  • Document the deployment process and maintain logs of changes for auditing.
  • Leverage RMM tools like NinjaOne to deploy the script at scale and monitor outcomes.
  • Avoid setting timeout to 0 unless there is a specific, justified need.

Final Thoughts

As IT environments scale, so does the need for secure, consistent, and automated configurations. This script exemplifies how even simple shell scripting can enforce best practices without complex infrastructure. For MSPs and IT admins using NinjaOne, integrating such scripts into automated policies enhances operational efficiency and security posture.

NinjaOne’s automation capabilities—like scheduled scripts, policy-based deployment, and centralized monitoring—make it the ideal platform to deploy and manage configurations like LoginGraceTime. When paired with well-crafted scripts like this one, NinjaOne empowers teams to deliver secure, scalable, and responsive IT management.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service delivery tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).