You log in to a fresh server and see warnings like these:

-bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LANGUAGE = (unset),
        LC_ALL = (unset),
        LC_CTYPE = "UTF-8",
        LANG = "en_US.UTF-8"
    are supported and installed on your system.

The cause is almost always one of two things. Either the locale isn’t generated on the server, or your SSH client forwards your local machine’s locale, which the server doesn’t have. Here’s how to fix both.

What a locale is

A locale defines language and formatting: character encoding (UTF-8), date and number formats, sort order and message language. It’s controlled by environment variables:

Variable Controls
LANG Default for everything
LC_CTYPE, LC_TIME, LC_NUMERIC, … Individual categories
LC_ALL Overrides everything (use for testing only)
LANGUAGE Message language preference list

Check yours:

locale
locale -a          # locales available on this system

Fix 1: generate the locale

Debian / Ubuntu

sudo apt install locales
sudo locale-gen en_US.UTF-8
sudo update-locale LANG=en_US.UTF-8

Or choose interactively:

sudo dpkg-reconfigure locales

On Debian, locale-gen builds the locales enabled in /etc/locale.gen. Uncomment the line (en_US.UTF-8 UTF-8) and run sudo locale-gen.

RHEL, Rocky, AlmaLinux, Fedora

Locales come as language packs:

sudo dnf install glibc-langpack-en
sudo localectl set-locale LANG=en_US.UTF-8

Log out and back in to apply.

Fix 2: stop SSH from forwarding your local locale

macOS and many desktop Linux setups send LANG and LC_* through SSH. If your Mac uses de_DE.UTF-8 or the odd LC_CTYPE=UTF-8, the server tries to use it and complains.

Server side, you can stop accepting them. In /etc/ssh/sshd_config, comment out:

#AcceptEnv LANG LC_*

Then sudo systemctl reload ssh (or sshd).

Client side, you can stop sending them. In ~/.ssh/config on your computer, there’s no clean per-option switch, so the usual fix is in the system-wide client config (/etc/ssh/ssh_config). Comment out SendEnv LANG LC_*. On macOS, Terminal’s “Set locale environment variables on startup” option affects this too.

Alternatively, generate the locale your client sends (Fix 1). Then everything matches.

Set the system default with localectl

sudo localectl set-locale LANG=en_US.UTF-8
localectl status

This writes /etc/default/locale (Debian/Ubuntu) or /etc/locale.conf (RHEL).

C.UTF-8: the minimal choice

C.UTF-8 is built into modern glibc and is always available. It gives UTF-8 encoding with plain, byte-order (“C”) sorting and English messages. It’s a great default for servers and containers when you don’t need language-specific formatting:

sudo localectl set-locale LANG=C.UTF-8

In Dockerfiles:

ENV LANG=C.UTF-8

Why it matters beyond the warnings

  • Python: a missing UTF-8 locale used to cause UnicodeEncodeError when printing non-ASCII text. Python 3.7+ coerces to UTF-8 in most cases, but older tools still trip.
  • PostgreSQL: the database cluster’s collation comes from the locale at initdb time. It affects sort order and indexes. Choose it deliberately, and keep it consistent across replicas.
  • Sorting in scripts: sort and ls order differs between C and en_US.UTF-8. Use LC_ALL=C sort in scripts for predictable, fast results. See sort and uniq.
  • Number formats: in some locales the decimal separator is a comma, which can break scripts that parse numbers.

Don’t set LC_ALL permanently

LC_ALL overrides everything and is meant for one-off commands:

LC_ALL=C grep -a pattern binaryish.log

Setting it in /etc/environment or .bashrc hides other problems and can produce these very warnings if the locale is missing.

Quick reference

Task Command
Show current locale
List available locale -a
Generate (Debian/Ubuntu) sudo locale-gen en_US.UTF-8
Set default sudo localectl set-locale LANG=en_US.UTF-8
RHEL language pack sudo dnf install glibc-langpack-en
Minimal UTF-8 LANG=C.UTF-8
Stop SSH forwarding comment AcceptEnv LANG LC_* in sshd_config

Related: hostname, time zone and environment variables.

  • Linux
  • Configuration
  • Troubleshooting