---
title: Set SSH MaxSessions limit
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: Docs > Datadog Security > OOTB Rules > Set SSH MaxSessions limit
---

> For the complete documentation index, see [llms.txt](https://docs.datadoghq.com/llms.txt).

# Set SSH MaxSessions limit
 
## Description{% #description %}

The `MaxSessions` parameter specifies the maximum number of open sessions permitted from a given connection. To set MaxSessions edit `/etc/ssh/sshd_config` as follows:

```
MaxSessions 10
```

The sshd default of 10 sessions applies when the configuration omits `MaxSessions`, and complies when the limit is 10 or more.

## Rationale{% #rationale %}

To protect a system from denial of service due to a large number of concurrent sessions, use the rate limiting function of MaxSessions to protect availability of sshd logins and prevent overwhelming the daemon.

## Remediation{% #remediation %}

### Shell script{% #shell-script %}

The following script can be run on the host to remediate the issue.

```bash
#!/bin/bash

# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}' 'linux-base' 2>/dev/null | grep -q '^installed$'; then

var_sshd_max_sessions='10'

mkdir -p /etc/ssh/sshd_config.d
chmod 0700 /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
# sshd reads /etc/ssh/sshd_config.d through an Include line of /etc/ssh/sshd_config.
if grep -Eiqs '^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf' /etc/ssh/sshd_config; then
    if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
        LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        chmod 0644 "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

    cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
    # Insert at the beginning of the file
    printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
else
    if [ -e "/etc/ssh/sshd_config" ] ; then
        LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
        chmod 0600 "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert at the beginning of the file
    printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config"
    cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
```

### Ansible playbook{% #ansible-playbook %}

The following playbook can be run with Ansible to remediate the issue.

```gdscript3
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions
- name: XCCDF Value var_sshd_max_sessions # promote to variable
  set_fact:
    var_sshd_max_sessions: !!str 10
  tags:
    - always

- name: Set SSH MaxSessions limit - Find if a Match block of /etc/ssh/sshd_config
    sets the parameter MaxSessions
  ansible.builtin.find:
    paths:
    - /etc/ssh
    patterns: sshd_config
    contains: (?ims)^[ \t]*Match[ \t].*^[ \t]*MaxSessions[ \t]
    read_whole_file: true
  register: _sshd_main_config_match_sets_parameter
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions

- name: Set SSH MaxSessions limit - Remove the parameter MaxSessions from the Match
    blocks of /etc/ssh/sshd_config
  ansible.builtin.replace:
    path: '{{ item.path }}'
    after: (?im)^[ \t]*Match[ \t]
    regexp: (?i)^[ \t]*MaxSessions[ \t].*\n?
    replace: ''
  loop: '{{ _sshd_main_config_match_sets_parameter.files }}'
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions

- name: Set SSH MaxSessions limit - Find the files of /etc/ssh/sshd_config.d where
    a Match block sets the parameter MaxSessions
  ansible.builtin.find:
    paths:
    - /etc/ssh/sshd_config.d
    patterns: '*.conf'
    contains: (?ims)^[ \t]*Match[ \t].*^[ \t]*MaxSessions[ \t]
    read_whole_file: true
  register: _sshd_config_dir_match_sets_parameter
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions

- name: Set SSH MaxSessions limit - Remove the parameter MaxSessions from the Match
    blocks of the files of /etc/ssh/sshd_config.d
  ansible.builtin.replace:
    path: '{{ item.path }}'
    after: (?im)^[ \t]*Match[ \t]
    regexp: (?i)^[ \t]*MaxSessions[ \t].*\n?
    replace: ''
  loop: '{{ _sshd_config_dir_match_sets_parameter.files }}'
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions

- name: Set SSH MaxSessions limit - Check if /etc/ssh/sshd_config includes /etc/ssh/sshd_config.d
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: (?i)^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf
    state: absent
  check_mode: true
  changed_when: false
  failed_when: false
  register: _sshd_config_includes_config_dir
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions

- name: Set SSH MaxSessions limit - Set the parameter MaxSessions in /etc/ssh/sshd_config.d
  block:

  - name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured
      in /etc/ssh/sshd_config
    ansible.builtin.lineinfile:
      path: /etc/ssh/sshd_config
      regexp: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
      state: absent
    check_mode: true
    changed_when: false
    register: _config_file_has_parameter

  - name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured
      in /etc/ssh/sshd_config.d
    ansible.builtin.find:
      paths:
      - /etc/ssh/sshd_config.d
      contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
      patterns: '*.conf'
    register: _config_dir_has_parameter

  - name: Set SSH MaxSessions limit - Count the lines that configure the parameter
      MaxSessions in /etc/ssh/sshd_config.d
    ansible.builtin.lineinfile:
      path: '{{ item.path }}'
      regexp: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
      state: absent
    check_mode: true
    changed_when: false
    loop: '{{ _config_dir_has_parameter.files }}'
    register: _config_dir_parameter_lines

  - name: Set SSH MaxSessions limit - Check if /etc/ssh/sshd_config exists
    ansible.builtin.stat:
      path: /etc/ssh/sshd_config
    register: _config_file_exists

  - name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured
      correctly in /etc/ssh/sshd_config
    ansible.builtin.lineinfile:
      path: /etc/ssh/sshd_config
      regexp: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+{{ var_sshd_max_sessions
        }}$
      state: absent
    check_mode: true
    changed_when: false
    register: _config_file_correctly
    when: _config_file_exists.stat.exists

  - name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured
      correctly in /etc/ssh/sshd_config.d
    ansible.builtin.find:
      paths:
      - /etc/ssh/sshd_config.d
      contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+{{ var_sshd_max_sessions
        }}$
      patterns: '*.conf'
    register: _config_dir_correctly

  - name: Set SSH MaxSessions limit
    block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
        mode: '0600'
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      ansible.builtin.stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter MaxSessions is present in /etc/ssh/sshd_config.d
      ansible.builtin.find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
        patterns: '*.conf'
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      ansible.builtin.lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
        mode: '0600'
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files | default([]) }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched > 0

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
        mode: '0600'
        line: MaxSessions {{ var_sshd_max_sessions }}
        state: present
        insertbefore: BOF
        validate: /usr/sbin/sshd -t -f %s
    when:
    - _config_file_correctly is not skipped
    - (_config_file_correctly.found == 0 and _config_dir_correctly.matched == 0) or
      ((_config_file_has_parameter.found | int) + (_config_dir_parameter_lines.results
      | map(attribute='found') | map('int') | sum)) != 1

  - name: Set SSH MaxSessions limit - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
    ansible.builtin.file:
      path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      mode: '0600'
      state: touch
      modification_time: preserve
      access_time: preserve
  when:
  - '"linux-base" in ansible_facts.packages'
  - (_sshd_config_includes_config_dir.found | default(0) | int) > 0
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions

- name: Set SSH MaxSessions limit - Set the parameter MaxSessions in /etc/ssh/sshd_config
  block:

  - name: Set SSH MaxSessions limit - Find the files of /etc/ssh/sshd_config.d that
      set the parameter MaxSessions
    ansible.builtin.find:
      paths:
      - /etc/ssh/sshd_config.d
      patterns: '*.conf'
      contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
    register: _sshd_config_dir_sets_parameter

  - name: Set SSH MaxSessions limit - Remove the parameter MaxSessions from the files
      of /etc/ssh/sshd_config.d
    ansible.builtin.lineinfile:
      path: '{{ item.path }}'
      regexp: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+
      state: absent
    loop: '{{ _sshd_config_dir_sets_parameter.files }}'

  - name: Set SSH MaxSessions limit
    block:

    - name: Check for duplicate values
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)(?i)^\s*MaxSessions\s+
        mode: '0600'
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)(?i)^\s*MaxSessions\s+
        mode: '0600'
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)(?i)^\s*MaxSessions\s+
        mode: '0600'
        line: MaxSessions {{ var_sshd_max_sessions }}
        state: present
        insertbefore: BOF
        validate: /usr/sbin/sshd -t -f %s
  when:
  - '"linux-base" in ansible_facts.packages'
  - (_sshd_config_includes_config_dir.found | default(0) | int) == 0
  tags:
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_set_max_sessions
```
