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.