Permission denied: что значит ошибка и как её исправить

опубликовано
читать
≈ 11 мин
автор
среда и версия
Debian 12: bash 5.2, coreutils 9.1, OpenSSH 9.2, Python 3.11; Docker CLI 27.5; PostgreSQL 17
содержание пройти тест Linux

Permission denied переводится как «доступ запрещён». Ошибка не про пароль и не про испорченный файл: ядро Linux отказалось выполнить операцию — прочитать, записать, запустить или войти в каталог, — потому что у пользователя, от имени которого работает команда, нет нужного права. Сообщение печатает программа, которая наткнулась на отказ, поэтому строка всегда устроена одинаково:

cat: /srv/team/report.txt: Permission denied

cat — кто получил отказ, /srv/team/report.txt — к чему не пустили, Permission denied — почему. Ниже — как за три команды найти, какого права не хватает, и все места, где встречается эта ошибка: файлы и каталоги, скрипты, sudo, SSH и git, Docker, Python и PostgreSQL. Весь вывод снят на чистом Debian 12.

Linux / 01

Как ядро решает, пустить ли тебя

Как ядро решает, пустить ли тебяТри проверки на примере пользователя alice и каталога /srv/app. Шаг 01, кто запрашивает: пользователь alice с группами alice и sudo, это показывает команда id. Шаг 02, какая роль: каталог drwxr-x--- принадлежит root и группе deploy, alice не root и не в deploy, поэтому для неё действуют права остальных — три прочерка. Шаг 03, нужный бит: чтобы войти в каталог app, нужен x, его нет — Permission denied. После usermod -aG deploy alice попадает в роль группы с правами r-x, и config.yml читается.проверкаalice и каталог /srv/appитог01 кто запрашиваетпользователь и его группыalice: alice, sudoid02 какая рольвладелец, группа или остальныеdrwxr-x--- root deployalice не root и не в deployостальные: ---03 нужный битr читать · w писать · x войтивойти в app — нужен xPermission deniedпосле usermod -aG deploy: роль «группа», r-x — config.yml читается
Ядро проверяет три вещи: кто запрашивает, какая из трёх ролей к нему относится и есть ли у этой роли нужный бит. alice упёрлась в каталог: у «остальных» на app нет даже x, поэтому права самого config.yml уже не важны.

Как найти причину: три команды

Права проверяются для конкретного пользователя и конкретного пути, поэтому диагностика всегда одна и та же.

Кто ты. id показывает пользователя и все его группы:

id
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo)

Что за файл. ls -l показывает владельца, группу и биты прав:

ls -l /srv/team/report.txt
-rw-------. 1 bob bob 34 Oct 27 09:40 /srv/team/report.txt

Файл принадлежит bob, права rw-------: читать и писать может только владелец. alice — не bob, и для неё действует третья тройка, ---. Точка после прав — метка SELinux хоста, на котором снимался вывод; в обычных Debian и Ubuntu её нет. Как читать эти девять символов, подробно разобрано в статье про chmod и права доступа.

Что на пути. Если с самим файлом всё в порядке, виноват каталог над ним. namei -l раскладывает путь и показывает права каждого звена:

namei -l /srv/app/config.yml
f: /srv/app/config.yml
drwxr-xr-x root root   /
drwxr-xr-x root root   srv
drwxr-x--- root deploy app
                       config.yml - Permission denied

Каталог app открыт только владельцу root и группе deploy. alice не входит ни туда, ни туда, поэтому до config.yml она не доходит вовсе — какие права у самого файла, уже неважно.

Файл: не хватает права чтения или записи

Самый частый случай — файл принадлежит другому пользователю или root:

cat /srv/team/report.txt
touch /etc/motd
cat: /srv/team/report.txt: Permission denied
touch: cannot touch '/etc/motd': Permission denied

Честных способов исправить три, от лучшего к худшему:

  1. Работать с файлом от имени владельца: sudo -u bob cat /srv/team/report.txt, а с системными файлами — через sudo.
  2. Дать доступ группе: владелец выставляет группу и chmod g+r, а тебя добавляют в эту группу. Так доступ раздают командам, а не людям по одному — подробнее в статье о пользователях и группах.
  3. Сменить владельца: sudo chown alice /srv/team/report.txt, если файл теперь твой.

chmod 777 в этом списке нет намеренно — о нём в разделе с ошибками.

Каталог: нет права войти

У каталога биты значат другое: r — прочитать список имён, w — создавать и удалять файлы внутри, x — войти и обращаться к файлам по имени. Без x закрыто всё, что лежит глубже:

ls /srv/app
cd /srv/app
cat /srv/app/config.yml
ls: cannot open directory '/srv/app': Permission denied
bash: cd: /srv/app: Permission denied
cat: /srv/app/config.yml: Permission denied

Каталог принадлежит группе deploy, поэтому правильное решение — добавить alice в эту группу:

sudo usermod -aG deploy alice

Новая группа появится только у процессов, запущенных после следующего входа в систему: выйди и зайди снова или открой новую SSH-сессию. В новой сессии:

id
cat /srv/app/config.yml
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),1002(deploy)
db_host: localhost

mkdir: cannot create directory: Permission denied

Создать файл или каталог — значит записать новое имя в родительский каталог. Для этого нужны w и x на родителе, а не на том, что создаёшь:

mkdir /opt/myapp
mkdir: cannot create directory '/opt/myapp': Permission denied

/opt принадлежит root. Создай каталог через sudo и сразу отдай его себе — sudo mkdir /opt/myapp && sudo chown alice: /opt/myapp — или работай в домашнем каталоге, где права есть по умолчанию.

Скрипт: ./deploy.sh: Permission denied

Чтобы запустить файл как программу, нужен бит x. У только что созданного скрипта его нет:

./deploy.sh
bash: ./deploy.sh: Permission denied

Исправление — chmod +x deploy.sh. Второй путь — передать скрипт интерпретатору явно: тогда файл нужно только прочитать, и x не требуется:

bash deploy.sh
деплой пошёл

Если x уже стоит, а ошибка осталась, посмотри на файловую систему. Каталоги вроде /tmp на серверах часто монтируют с опцией noexec, и запуск оттуда запрещён всем, даже root:

ls -l /mnt/scratch/deploy.sh
/mnt/scratch/deploy.sh
sudo /mnt/scratch/deploy.sh
findmnt -no OPTIONS /mnt/scratch
-rwxr-xr-x. 1 alice alice 43 Oct 27 09:41 /mnt/scratch/deploy.sh
bash: /mnt/scratch/deploy.sh: Permission denied
sudo: unable to execute /mnt/scratch/deploy.sh: Permission denied
rw,nosuid,nodev,noexec,relatime,seclabel,size=16384k,inode64

noexec в списке опций — ответ. Переложи скрипт в домашний каталог или запусти его через bash. Как написать первый скрипт и зачем ему #!/bin/bash, разобрано в статье про bash-скрипты.

sudo не помогает: sudo echo > файл

Классическая ловушка: команда запущена через sudo, а ошибка та же:

sudo echo "127.0.0.1 api.local" >> /etc/hosts
bash: /etc/hosts: Permission denied

Перенаправление >> выполняет твоя оболочка — ещё до запуска sudo и от твоего имени. Под root работает только echo, которому права не нужны. Писать в файл должна программа, запущенная через sudo, и для этого есть tee:

echo "127.0.0.1 api.local" | sudo tee -a /etc/hosts
127.0.0.1 api.local

tee -a дописывает строку в файл и повторяет её на экран. Как работают >, >> и |, разобрано в статье о пайпах и перенаправлениях.

Файлы, созданные через sudo

Обратная сторона: если запускать команды в своём проекте через sudo, созданные файлы достаются root, и потом тебе самому в них не записать:

mkdir site
sudo touch site/index.html
ls -l site
echo "<h1>Привет</h1>" >> site/index.html
total 0
-rw-r--r--. 1 root root 0 Oct 27 09:50 index.html
bash: site/index.html: Permission denied

Так ломаются проекты после sudo pip install или sudo npm install в рабочем каталоге. Верни файлы себе — sudo chown -R alice: site — и дальше работай без sudo. Python-пакеты ставь в виртуальное окружение, туда права root не нужны.

SSH и git: Permission denied (publickey)

Это сообщение не о правах на файлы. Сервер пускает только по ключу, а подходящего ключа ты не предъявил. При клонировании с GitHub это выглядит так:

git clone git@github.com:alice/project.git
Cloning into 'project'...
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Что пробовал клиент, показывает подробный режим ssh -v:

ssh -v -T git@github.com 2>&1 | grep -E "Authentications that can continue|Trying private key|No more authentication"
debug1: Authentications that can continue: publickey
debug1: Trying private key: /home/alice/.ssh/id_rsa
debug1: Trying private key: /home/alice/.ssh/id_ecdsa
debug1: Trying private key: /home/alice/.ssh/id_ecdsa_sk
debug1: Trying private key: /home/alice/.ssh/id_ed25519
debug1: Trying private key: /home/alice/.ssh/id_ed25519_sk
debug1: Trying private key: /home/alice/.ssh/id_xmss
debug1: Trying private key: /home/alice/.ssh/id_dsa
debug1: No more authentication methods to try.

Сервер принимает только publickey, а клиент перебрал стандартные имена ключей в ~/.ssh, не нашёл ни одного и сдался. Дальше два шага: создать ключ, если его нет, и положить открытую половину туда, где сервер её ищет:

ssh-keygen -t ed25519
cat ~/.ssh/id_ed25519.pub

Содержимое .pub добавь на GitHub в Settings → SSH and GPG keys, а на своём сервере — в ~/.ssh/authorized_keys нужного пользователя, проще всего командой ssh-copy-id. Если ключ лежит под другим именем, укажи его явно: ssh -i ~/.ssh/work_key или строкой IdentityFile в ~/.ssh/config. Как устроен вход по ключу и чем ещё может закончиться подключение, разобрано в статье про SSH.

Docker: permission denied while trying to connect to the Docker daemon socket

docker ps
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.47/containers/json": dial unix /var/run/docker.sock: connect: permission denied

Команда docker только клиент: она передаёт запрос демону через сокет /var/run/docker.sock. А сокет открыт лишь root и группе docker:

ls -l /var/run/docker.sock
srw-rw----. 1 root docker 0 Oct 27 09:48 /var/run/docker.sock

Исправление — добавить себя в группу docker и перезайти:

sudo usermod -aG docker $USER

После нового входа или newgrp docker в текущем терминале docker ps работает без sudo. Учти, что группа docker равносильна root: кто может запускать контейнеры, тот может смонтировать в контейнер любой каталог хоста. На общих серверах вместо этого используют rootless-режим Docker или Podman. Как собрать образ и поднять несколько контейнеров, рассказано в статьях про Dockerfile и Docker Compose.

Python: PermissionError: [Errno 13] Permission denied

Python сообщает о том же отказе ядра своим исключением, а 13 — номер кода ошибки EACCES. Скрипт report.py:

with open("/srv/team/report.txt", encoding="utf-8") as f:
    print(f.read())
Traceback (most recent call last):
  File "/home/alice/report.py", line 1, in <module>
    with open("/srv/team/report.txt", encoding="utf-8") as f:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/srv/team/report.txt'

Путь в сообщении — тот самый файл, проверь его через ls -l и namei -l, как в разделах выше. В Windows у этой ошибки свои частые причины: файл открыт в Excel или другой программе, запись идёт в C:\Program Files или в open() передан путь к папке, а не к файлу. В Linux последний случай выглядит иначе — IsADirectoryError: [Errno 21] Is a directory. Как перехватить исключение в коде, рассказано в статье про try/except, а чтение и запись файлов — в материале о работе с файлами.

PostgreSQL: permission denied for table, schema, sequence

У базы данных свои права, и сообщение похожее. Роль app подключилась к базе shop, но таблица orders принадлежит другой роли:

SELECT * FROM orders;
ERROR:  permission denied for table orders

Права в PostgreSQL выдаёт владелец объекта командой GRANT:

GRANT SELECT, INSERT ON orders TO app;

Теперь чтение работает, но вставка упирается в последовательность — id в этой таблице объявлен как serial:

INSERT INTO orders (customer, amount) VALUES ('Борис', 800);
ERROR:  permission denied for sequence orders_id_seq

serial берёт следующий номер из отдельного объекта, последовательности orders_id_seq, и на неё нужно своё право:

GRANT USAGE ON SEQUENCE orders_id_seq TO app;

После этого та же вставка проходит:

INSERT INTO orders (customer, amount) VALUES ('Борис', 800);
SELECT * FROM orders;
INSERT 0 1
 id | customer | amount 
----+----------+--------
  1 | Анна     |   1200
  2 | Борис    |    800
(2 rows)

Столбцу GENERATED ALWAYS AS IDENTITY отдельное право на последовательность не нужно, хватает INSERT на таблицу, — ещё одна причина выбирать его вместо serial в новых таблицах (как объявить такой столбец).

Начиная с PostgreSQL 15 создавать таблицы в схеме public может только владелец базы, поэтому новая роль видит такое:

CREATE TABLE notes (id int);
ERROR:  permission denied for schema public
LINE 1: CREATE TABLE notes (id int);
                     ^

Есть два решения: выдать право на схему — GRANT USAGE, CREATE ON SCHEMA public TO app; — или сделать роль владельцем базы: ALTER DATABASE shop OWNER TO app;. Чтобы права на таблицы, которые владелец создаст позже, выдавались сами, есть ALTER DEFAULT PRIVILEGES.

Permission denied или Operation not permitted

Это две разные ошибки. Permission denied (код EACCES) значит, что операцию не разрешают биты прав на файл или путь, а другой набор битов её бы разрешил. Operation not permitted (EPERM) значит, что операцию может выполнить только привилегированный процесс, сколько бы прав ни было на файле. Пример — передать свой файл другому пользователю:

chown bob deploy.sh
chown: changing ownership of 'deploy.sh': Operation not permitted

Менять владельца файла может только root: sudo chown bob deploy.sh.

Ошибки, на которых спотыкаются

chmod 777, чтобы ошибка ушла. Ошибка уйдёт, но любой процесс в системе получит право переписать файл. Правильный вопрос — какой роли какого бита не хватает; обычно ответ — chmod +x, chown или группа. SSH, к слову, откажется работать с закрытым ключом, который могут читать посторонние.

sudo перед каждой командой. Ошибка пропадает сейчас и возвращается позже: файлы проекта переходят к root, и обычный запуск уже не может их записать.

usermod -G без -a. Без -a команда не добавляет группу, а заменяет весь список дополнительных групп — так легко потерять, например, sudo. Пиши usermod -aG.

Группа без перезахода. После usermod -aG текущая сессия про новую группу не знает, и id в ней показывает прежний список. Нужен новый вход или newgrp.

Права проверили у файла, а запрет на каталоге. ls -l может показать у файла rw-r--r--, а доступа всё равно нет: не хватает x на одном из каталогов выше. namei -l показывает весь путь сразу.

Частые вопросы

Как переводится Permission denied

«Доступ запрещён», дословно — «в разрешении отказано». У пользователя, от имени которого работает программа, нет права на операцию с файлом, каталогом или другим ресурсом.

Что значит Permission denied (publickey,password)

В скобках SSH перечисляет способы входа, которые разрешает сервер. Ни один не сработал: ключа нет или он не добавлен на сервер, а пароль неверный или его не спросили. Разбор — в разделе про SSH выше.

Почему root тоже получает Permission denied

Root обходит обычные биты прав, но не всё. Запуск с файловой системы с noexec запрещён и ему — пример есть выше. В дистрибутивах с SELinux (Fedora, RHEL) или AppArmor (Ubuntu) запрет может прийти от политики безопасности: права в ls -l в порядке, а доступа нет. Метку SELinux показывает ls -Z, отказы политики пишутся в журнал аудита. В Docker на таких системах этим грешат каталоги хоста, подключённые через -v: помогает суффикс :Z у тома.

Чем Permission denied отличается от Access denied

По смыслу это одно и то же, просто так пишут другие программы — Windows, MySQL (Access denied for user 'root'@'localhost' — неверный пароль или у пользователя нет прав на базу). Ядро Linux всегда отвечает Permission denied.

Источники

Выжимки статей в Telegram: одна ловушка, код с выводом и ссылка на полный разбор. t.me/koddo_ru