How to Use Shell Scripting to Set MaxAuthTries in Linux

Configuring secure authentication parameters on Linux systems is a foundational step in defending infrastructure from brute-force attacks. One critical setting is MaxAuthTries, which limits the number of authentication attempts allowed per SSH connection. Left at its default value—or worse, misconfigured—this setting can leave a system vulnerable to persistent intrusion attempts.

For IT professionals and Managed Service Providers (MSPs), learning how to use shell scripting to set MaxAuthTries in Linux ensures consistent security policies across machines. This post explains a shell script purpose-built to set MaxAuthTries reliably and safely.

Background

Linux’s SSH daemon (sshd) includes a variety of tunable parameters in the /etc/ssh/sshd_config file. Among these, MaxAuthTries is especially significant in hardening systems. It defines the number of authentication attempts permitted per connection before the server disconnects. The default is often 6, which may be too lenient in many enterprise contexts.

For MSPs managing hundreds or thousands of endpoints, manual SSH configuration is inefficient and error-prone. Automating this task with a shell script enables centralized control, versioned backups, and reduced misconfiguration risk. This script meets those needs by modifying sshd_config safely and restarting the service if necessary.

The Script

#!/usr/bin/env bash

# Description: Sets the SSH MaxAuthTries.
# 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: --numberOfRetries "ReplaceMeWithANumber"
#   The number of authentication attempts permitted per connection. The default is 6.
#
# Links: https://man.openbsd.org/sshd_config#MaxAuthTries

# 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 [[ -z "${numberOfRetries}" ]]; then
    die "[Error] NumberOfRetries was not specified." 1
fi

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

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

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

_should_reload="false"

# Default is 0; which is disabled
_maxAuthTries="MaxAuthTries ${numberOfRetries}"

# Check if the sshd_config file exists
if [[ -f "${_sshd_config}" ]]; then
    _should_backup="false"
    # Check if the MaxAuthTries option is already set to _maxAuthTries
    if grep -q "^${_maxAuthTries}" "${_sshd_config}"; then
        echo "[Info] Timeout is already set to ${numberOfRetries}."
        _should_reload="false"
    elif grep -q "^MaxAuthTries .*" "${_sshd_config}"; then
        _should_backup="true"
        # First check if the option is not commented out and set to yes
        # Then set the MaxAuthTries option to ${numberOfRetries}
        sed -i "s/^MaxAuthTries.*/${_maxAuthTries}/" "${_sshd_config}"
        echo "[Info] MaxAuthTries set to ${numberOfRetries}."
        _should_reload="true"
    elif grep -q "^#MaxAuthTries" "${_sshd_config}"; then
        _should_backup="true"
        # First check if the option is commented out
        # Then set the MaxAuthTries option to ${numberOfRetries}
        sed -i "s/^#MaxAuthTries.*/${_maxAuthTries}/" "${_sshd_config}"
        echo "[Info] MaxAuthTries set to ${numberOfRetries}, as it was commented out."
        _should_reload="true"
    else
        _should_backup="true"
        # Append the MaxAuthTries 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 "${_maxAuthTries}" >>"${_sshd_config}"
        echo "[Info] MaxAuthTries set to ${numberOfRetries} at the end of the sshd_config file."
        _should_reload="true"
    fi

    if [[ "${_should_backup}" == "true" ]]; then
        backup_file "${_sshd_config}"
    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

Here’s how the script accomplishes its goal of setting MaxAuthTries in Linux using shell scripting:

1. Parameter Validation

The script begins by checking if the numberOfRetries variable is set, validating that it falls within the acceptable range (0 to 86400), and stripping any leading zeros to ensure proper interpretation.

2. Backup Mechanism

Before making any modifications, the script creates a timestamped backup of the current sshd_config. If more than three backups exist, it deletes the oldest ones to avoid unnecessary storage bloat.

3. Configuration Update

The script then checks for existing MaxAuthTries entries:

  • If the correct value is already set, it exits quietly.
  • If the setting exists but with a different value, it uses sed to update the line.
  • If the setting is commented out, it updates the line accordingly.
  • If not present at all, it appends the setting to the file.

4. Service Reload

Depending on the system’s init system (Systemd or SysVinit), it identifies the SSH service (sshd, ssh, or openssh-server) and:

  • Checks if it’s enabled and running.
  • Reloads or restarts the service only if the configuration has changed.

The script includes robust error handling and clear logging at every step, ensuring transparency during automated execution.

Potential Use Cases

Consider an MSP managing Linux VMs across multiple client environments. One client mandates that no system should allow more than 3 authentication attempts to mitigate brute-force attempts. Instead of manually logging into each device, the engineer pushes this script via NinjaOne to all endpoints, passing –numberOfRetries 3. The script ensures compliance, logs changes, and creates backups in case rollback is needed.

Comparisons

Manual Configuration

Manually editing /etc/ssh/sshd_config is viable for one or two machines. But this approach doesn’t scale, lacks auditability, and is prone to human error.

Configuration Management Tools

Ansible or Puppet could also manage sshd_config, but they introduce dependencies and a steeper learning curve. This shell script strikes a balance between simplicity and automation—ideal for small-to-mid-sized MSPs or one-off configuration tasks.

Other Shell Scripts

Many public scripts blindly append configurations or overwrite entire config files. This script distinguishes itself by safely editing only the necessary line and preserving original files through backups.

FAQs

Q: What happens if the sshd_config file is missing?

A: The script exits with an error and does not proceed, ensuring it won’t make incorrect assumptions.

Q: Can this script run on any Linux distribution?

A: Yes, it’s compatible with both Systemd-based and SysVinit-based systems, making it widely portable.

Q: Will existing comments or formatting be preserved?

A: Yes, the script only targets MaxAuthTries lines and leaves all other configurations untouched.

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

A: The script notifies the user but doesn’t force-start it, respecting existing service states.

Implications

Misconfigured MaxAuthTries settings can expose servers to brute-force attacks. By enforcing stricter limits, you reduce the attack surface significantly. Automating this with a script ensures that systems adhere to internal security policies and external compliance standards (e.g., CIS Benchmarks, ISO 27001).

The broader implication is greater operational confidence. Backed-up changes and automatic validation reduce the risk of accidental lockouts or misconfigurations that could lead to downtime.

Recommendations

  • Test in a non-production environment first. This ensures there are no unexpected impacts from service reloads or syntax errors.
  • Pair with monitoring tools. Verify SSH availability post-deployment to catch edge cases where sshd might not restart properly.
  • Log outputs centrally. Store script logs via your RMM or SIEM for traceability.
  • Use argument sanitization. If integrating into a larger automation pipeline, ensure user input is validated externally as well.

Final Thoughts

For IT teams and MSPs, managing SSH settings like MaxAuthTries through automation is essential for consistency, compliance, and security. This script provides a lightweight, reliable way to enforce authentication attempt limits on Linux systems, complete with safety checks and service-aware reloading.

Using NinjaOne, you can deploy this script at scale, audit the outcomes, and automate recurring security tasks. NinjaOne’s custom scripting and policy-driven automation make it the perfect platform to operationalize configuration management without complex third-party tooling.

By combining intelligent scripting with a modern endpoint management platform, you streamline your workflows and improve your clients’ security postures—one line of code at a time.

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).