How to Fix SSH Error: “Bad owner or permissions on ~/.ssh/config”

When attempting to establish an SSH connection to a remote server, you might encounter the error message: Bad owner or permissions on ~/.ssh/config. This issue typically arises because the SSH client enforces strict security rules for its configuration files to prevent unauthorized access or modification.

This article will explore the reasons behind this error and offer a comprehensive set of solutions to rectify it, ensuring that your SSH connections can be established securely and without interruption.

Understanding the SSH Configuration File Security

The SSH (Secure Shell) client relies on configuration files, primarily ~/.ssh/config, to manage connection parameters, host-specific settings, and private keys. Due to the sensitive nature of this information, SSH mandates that these files, especially the config file and private keys, must have restrictive permissions.

The core principle is that only the file owner should have read and write access to the ~/.ssh/config file. Suppose the permissions are too open (e.g., allowing other users or groups to write to the file). In that case, SSH considers it a security risk and refuses to use the configuration, leading to the “Bad owner or permissions” error. This strictness prevents malicious actors or accidental changes from compromising your SSH setup.

Solutions to Fix “Bad owner or permissions on ~/.ssh/config”

Here are several methods to resolve this SSH configuration error, ranging from permission adjustments to file ownership corrections.

1. Adjusting File Permissions (Most Common Fix)

The most frequent cause of this error is incorrect file permissions on the ~/.ssh/config file. It should be readable and writable only by the owner.

To set the correct permissions (rw------- or 600), execute the following command:

admin@technofossy.com:~$ chmod 600 ~/.ssh/config

In some cases, read-only permission (400) for the owner might also suffice if you do not intend to edit the file directly frequently, though 600 is generally recommended for a configuration file you might need to modify.

2. Verifying and Correcting File Ownership

Another common issue is that the ~/.ssh/config file might not be owned by the current user. SSH requires that the user attempting the connection is the owner of their SSH configuration file.

To check the current owner and permissions, use:

admin@technofossy.com:~$ ls -la ~/.ssh/config

-rw——- 1 your_user your_group 31 Mar 29 11:04 /home/your_user/.ssh/config

Replace your_user and your_group with your actual username and group. If the owner is incorrect (e.g., root), change it back to your user. You can use $USER to automatically use the current logged-in username.

admin@technofossy.com:~$ chown $USER ~/.ssh/config

To ensure both user and group ownership are correct, especially if you want to be explicit or if group settings are a concern:

admin@technofossy.com:~$ chown $USER:$USER ~/.ssh/config

If multiple files within the ~/.ssh directory have incorrect ownership, you can apply the change recursively to the entire directory (use with caution):

admin@technofossy.com:~$ sudo chown -R $USER:$USER ~/.ssh

Note: You might need sudo if the files are currently owned by another user, like root.

Read: How to Fix SSH ‘Permission denied (publickey)’; Authentication Failures

3. Recommended Permissions for the Entire ~/.ssh Directory

It’s good practice to ensure all files and the directory itself within ~/.ssh have appropriate permissions. Here’s a general guideline:

  • For /.ssh: use the sode snippet :

    user@host:~$ cat validate_directory_algorithm.txt
    # Algorithm: validate_directory_path
    
    # Purpose: Validates the security of parent directories of a given path,
    # iterating upwards towards root or a specified home directory.
    
    # Inputs:
    #   path_to_check: The initial path whose ancestors are to be validated.
    #   home_directory_path: The path to the user's home directory (boundary).
    #   user_id: The UID of the current user for ownership checks.
    #   check_home_boundary_flag: Boolean, if true, stop at home_directory_path.
    #   error_message_string_ref: A reference to store error messages.
    
    # Returns:
    #   0 on success (all checked directories are secure).
    #  -1 on failure (an insecure directory was found or an error occurred).
    
    FUNCTION validate_directory_path(path_to_check, home_directory_path, user_id,
                                     check_home_boundary_flag, OUT error_message_string_ref):
    
        current_path = path_to_check
    
        LOOP FOREVER:
            # 1. Get parent directory path of the current_path
            parent_path = get_parent_directory(current_path)
            
            IF parent_path IS NULL OR FAILED_TO_GET_PARENT:
                error_message_string_ref = "Failed to get parent directory for: " + current_path
                RETURN -1
    
            # 2. Update current_path to this parent for the current iteration's checks
            current_path = parent_path
            
            # 3. Check if directory exists and get its properties
            TRY:
                file_properties = get_file_info(current_path)
            EXCEPT (DOES_NOT_EXIST_ERROR OR PERMISSION_ERROR_TO_STAT):
                error_message_string_ref = "Cannot access directory: " + current_path
                RETURN -1
            
            # 4. Validate ownership and permissions
            is_system_owned = platform_is_system_owned_uid(file_properties.uid)
            is_user_owned = (file_properties.uid == user_id)
            
            # Secure permissions = No Group Write AND No Other Write (e.g., mode & 0o022 == 0)
            has_secure_permissions = ( (file_properties.mode & GROUP_WRITE_BIT) == 0 AND
                                       (file_properties.mode & OTHER_WRITE_BIT) == 0 )
                                       
            IF NOT (is_system_owned OR is_user_owned):
                error_message_string_ref = "Directory " + current_path + " has invalid ownership (UID: " + file_properties.uid + ")"
                RETURN -1
            
            IF NOT has_secure_permissions:
                error_message_string_ref = "Directory " + current_path + " has insecure permissions (Mode: " + OCTAL(file_properties.mode) + ")"
                RETURN -1
                
            # 5. Stop if we've reached the home directory boundary (if applicable)
            IF check_home_boundary_flag IS TRUE AND current_path == home_directory_path:
                BREAK LOOP
                
            # 6. Stop if we've reached filesystem root or "." (current directory marker)
            IF current_path == "/" OR current_path == ".":
                BREAK LOOP
                
        END LOOP
        
        RETURN 0  # Success
    END FUNCTION
    
    # --- Helper/Placeholder Function Explanations ---
    # get_parent_directory(path): Corresponds to POSIX `dirname()`.
    # get_file_info(path): Corresponds to POSIX `stat()`. Returns object with .uid, .mode.
    # platform_is_system_owned_uid(uid): Checks if UID is root (0) or other system UIDs.
    # GROUP_WRITE_BIT, OTHER_WRITE_BIT: Constants for permission checking (e.g., 0o020, 0o002).
    # OCTAL(value): Converts number to octal string.
    # error_message_string_ref: Output parameter for error messages.
  • For /config : use  readconf.c
  • For /authorized_keys : use the code below :
    user@host:~$ cat secure_authorized_keys_algorithm.txt
    # Algorithm: secure_ssh_authorized_keys
    
    # Purpose: Secures the SSH authorized_keys file by removing ACLs
    # and setting appropriate file permissions (644).
    
    # Inputs:
    #   user_home_directory_path: The absolute path to the user's home directory.
    
    # Returns:
    #   0 on success (file secured or does not exist).
    #   1 on failure (e.g., unable to set permissions).
    
    FUNCTION secure_ssh_authorized_keys(user_home_directory_path):
    
        keys_file_path = user_home_directory_path + "/.ssh/authorized_keys"
        
        # Check if the authorized_keys file exists and is a regular file
        IF file_exists(keys_file_path) AND is_regular_file(keys_file_path) THEN
        
            # Attempt to remove any existing ACLs; ignore errors (mimics '|| true')
            TRY:
                remove_all_acls(keys_file_path)
            CATCH ANY_ERROR_DURING_ACL_REMOVAL:
                PASS # Continue regardless of ACL removal outcome
                
            # Apply secure permissions (owner: read/write, group: read, other: read - typically 644)
            permissions_to_set = "rw-r--r--" # Symbolic or octal (e.g., 0o644)
            
            IF set_file_permissions(keys_file_path, permissions_to_set) IS SUCCESSFUL THEN
                RETURN 0  # Success
            ELSE
                display_warning_message("Unable to set proper permissions on " + keys_file_path)
                display_warning_message("Manual intervention required. Ensure the file owner has read access")
                display_warning_message("and that group/other users cannot modify the file.")
                print_newline()
                RETURN 1  # Failure
            END IF
            
        ELSE
            # File does not exist or is not a regular file.
            # Considered a success for this function's purpose as no action is needed on the file.
            RETURN 0 # Success
        END IF
        
    END FUNCTION
    
    # --- Helper/Placeholder Function Explanations ---
    # file_exists(path): Checks if a file or directory exists at the given path.
    # is_regular_file(path): Checks if the path points to a regular file.
    # remove_all_acls(path): Attempts to remove all Access Control Lists from the file.
    # set_file_permissions(path, mode): Sets the file's permissions (e.g., to "rw-r--r--" or 644).
    # display_warning_message(message): Outputs a warning message to the user.
    # print_newline(): Outputs a newline character.

You can set these systematically:

admin@technofossy.com:~$ chmod 0700 ~/.ssh
admin@technofossy.com:~$ chmod 0600 ~/.ssh/config
admin@technofossy.com:~$ chmod 0600 ~/.ssh/id_rsa # And other private keys
admin@technofossy.com:~$ chmod 0644 ~/.ssh/id_rsa.pub # And other public keys
admin@technofossy.com:~$ chmod 0600 ~/.ssh/authorized_keys
admin@technofossy.com:~$ chmod 0644 ~/.ssh/known_hosts

4. Solution for Windows Subsystem for Linux (WSL) Users

If you are using WSL and your ~/.ssh directory (or your entire home directory) is symlinked or mounted from your Windows filesystem, chmod commands might not have the intended effect by default. This is because WSL needs to be configured to handle Linux metadata correctly for files on Windows drives.

Read: How to Access Serial Ports (COM & ttyS) in Windows Subsystem for Linux (WSL1 & WSL2)

To enable metadata handling, you need to edit or create the /etc/wsl.conf file in your WSL distribution and add the following lines (this requires WSL build 17093 or later):

admin@technofossy.com:~$ sudo nano /etc/wsl.conf

Add this content to the file:

[automount]
options = “metadata”

After saving the file, you must restart WSL. You can do this by closing all WSL terminals and then reopening one, or by running wsl --shutdown in PowerShell/CMD and then restarting your WSL distribution.

Once WSL restarts with metadata enabled, chmod commands applied to files on mounted Windows drives should work as expected, allowing you to set the correct permissions for your ~/.ssh/config file.

5. When to Consider Removing or Recreating the Config File

In some situations, the ~/.ssh/config file might be empty, corrupted, or contain auto-generated content from tools (like SourceTree or Vagrant) that is no longer needed or is causing conflicts.

If you suspect this, and the file doesn’t contain critical configurations you need, you can try renaming or deleting it:

Rename (backup):

admin@technofossy.com:~$ mv ~/.ssh/config ~/.ssh/config.backup

Delete (if you are sure it’s not needed or empty):

admin@technofossy.com:~$ rm ~/.ssh/config

For users encountering this with Vagrant on Windows, sometimes deleting the config file located at C:\Users\[YourUser]\.ssh\config (or its equivalent path used by Vagrant) can resolve the “Bad owner or permissions” error when running vagrant ssh. For example:

C:\Users\technofossy> del .ssh\config

After removing the problematic config file, try your SSH or vagrant ssh command again. If a config file is necessary, you can recreate it manually with the correct permissions.

6. Addressing Global IdentityFile Issues

Occasionally, a global IdentityFile setting within your ~/.ssh/config might cause issues if the specified key is not appropriate for all connections or has permission problems itself. If you have a line like IdentityFile ~/.ssh/id_rsa at the top level of your config (not within a specific Host block), SSH will try to use this key for all connections. If this key is not suitable or has its own permission issues, it can indirectly contribute to connection problems. Review your ~/.ssh/config for such global settings and ensure they are intended or move them into specific Host blocks if necessary.

Verification

After applying any of the solutions above, attempt your SSH connection again:

admin@technofossy.com:~$ ssh user@hostname

If the “Bad owner or permissions” error is gone, the issue has been resolved. You should now be prompted for a password or connect via your SSH key if configured.

Conclusion

The “Bad owner or permissions on ~/.ssh/config” error is a common safeguard in SSH, ensuring your configuration remains secure. By understanding the necessity for strict permissions and applying the appropriate chmod and chown commands, or addressing WSL-specific configurations, you can quickly resolve this issue and restore your SSH connectivity.

 

 

Alex Chen

Alex is a seasoned Linux Systems Administrator and DevOps Engineer with over 12 years of experience architecting and maintaining high-availability infrastructure. He has a deep expertise in kernel tuning, shell scripting, containerization (Docker, Kubernetes), and implementing robust CI/CD pipelines. Alex is passionate about open-source software and finding elegant, automated solutions to complex IT challenges across various distributions.