Solving the MySQL Docker "Permission Denied" Error on Synology NAS: A Step-by-Step Guide
Content
## The Problem
Deploying MySQL using Docker on a Synology NAS is a common practice for setting up a reliable database service quickly. However, many users encounter a classic permission issue when mounting volumes, which causes the container to fail on startup. The logs typically show an error like `Could not open file '...' for error logging: Permission denied`. This article, based on a real-world case from `wiki.lib00.com`, will explain the cause of this problem and provide effective solutions.
---
## Reproducing the Failure
A developer, DP@lib00, attempted to deploy a `mysql:5.7.40` container, mapping volumes for configuration, logs, and data. Here are the two attempts and their outcomes.
### First Attempt: Failure
1. **Action**: The required folder structure, such as `/volume1/docker/mysql-5.7.40/logs` and `/volume1/docker/mysql-5.7.40/data`, was created using the Synology DSM File Station GUI.
2. **Docker Command**:
```bash
docker run -d --restart=always --name ee-mysql-5.7.40 -p 38756:3306 \
-v /volume1/docker/mysql-5.7.40/conf:/etc/mysql/conf.d \
-v /volume1/docker/mysql-5.7.40/logs:/logs \
-v /volume1/docker/mysql-5.7.40/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7.40
```
3. **Error Log**: The container exited immediately after starting, with a clear permission error in the logs.
```log
2025-11-27T14:34:47.228587Z 0 [ERROR] Could not open file '/logs/error.log' for error logging: Permission denied
2025-11-27T14:34:47.228609Z 0 [ERROR] Aborting
```
### Second Attempt: Success
1. **Action**: The old directories were deleted. After logging into the Synology via SSH, the folders were recreated via the command line, and critically, the permissions for the `logs` and `data` directories were changed.
```bash
# 1. Create directories (steps omitted)
# 2. Change permissions
chmod 777 /volume1/docker/mysql-5.7.40/logs
chmod 777 /volume1/docker/mysql-5.7.40/data
```
2. **Docker Command**: The same `docker run` command was used.
3. **Result**: The container started successfully and ran without issues.
---
## Root Cause Analysis: UID/GID Mismatch
The core of the problem is a mismatch between the **user running the MySQL service inside the Docker container** and the **owner/permissions of the folders on the Synology NAS host**.
1. **User Inside the Container**: For security reasons, the official MySQL Docker image does not run the service as the `root` user. Instead, it uses a specific, non-root user named `mysql`, which typically has a UID (User ID) and GID (Group ID) of `999`.
2. **Folders on the Host**: When you create folders through the Synology DSM GUI, their default owner is the currently logged-in user (e.g., `admin` or your personal account, whose UID/GID is not `999`). The default permissions are usually `755`. A `755` permission set means only the folder's owner has write access, while group members and others only have read and execute permissions.
3. **The Conflict**: When the Docker container starts, the `mysql` user (UID `999`) inside it tries to write files to the mapped host directories (`/logs` and `/var/lib/mysql`). From the Synology host's perspective, an "other" user with UID `999` is attempting to write to a folder it doesn't own. Because of the restrictive permissions, this operation is denied, leading to the `Permission denied` error.
The second attempt succeeded because the `chmod 777` command sets the folder permissions to `rwxrwxrwx`, which grants read, write, and execute permissions to **everyone** (owner, group, and **all other users**). This naturally includes the `mysql` user from within the container.
---
## Solutions
While `chmod 777` is a quick and effective fix, it grants excessive permissions and can be a security risk. We recommend a safer and more professional solution.
### Solution 1: Change Folder Ownership (Recommended)
This is the best practice for resolving this type of issue. We simply need to change the owner of the host directories to match the UID and GID of the `mysql` user inside the container.
1. **Confirm UID/GID**: For the official MySQL image, the UID and GID are typically `999`.
2. **Execute Command**: Log into your Synology NAS via SSH and run the following commands:
```bash
# Recursively change the owner and group of the lib00-mysql-5.7.40 directories to 999
sudo chown -R 999:999 /volume1/docker/lib00-mysql-5.7.40/data
sudo chown -R 999:999 /volume1/docker/lib00-mysql-5.7.40/logs
```
After this change, the container can write to the folders even with `755` permissions, because the folder owner now matches the user in the container. This method, recommended by the DP@lib00 team, adheres to the principle of least privilege and is much more secure.
### Solution 2: Use `chmod 777` (Quick but Not Recommended)
As shown in the successful attempt, granting `777` permissions resolves the issue quickly. However, you should only use this in development environments or when you are certain there are no security implications.
---
## Conclusion
Understanding and correctly managing file permissions is crucial when using persistent volumes in Docker. This is especially true on multi-user systems like Synology NAS, where user permission mapping between the host and container can be a common pitfall. When you encounter a `Permission denied` error, the preferred solution is to use `chown` to align the host directory ownership with the container process's UID/GID, as this is a more secure and professional approach than resorting to `chmod 777`.
Related Contents
Resolving PHP "could not find driver" Error: Ultimate Guide to Missing PDO Database Drivers
Duration: 00:00 | DP | 2026-07-04 08:03:00MySQL Practical Guide: Elegantly Adding Preference Columns to a User Table
Duration: 00:00 | DP | 2026-07-05 08:28:45How to Fix "Permission denied" Error When Running Shell Scripts in Mac/Linux
Duration: 00:00 | DP | 2026-07-06 08:54:30Resolving Nginx Permission Denied (13) Errors for WebP Images Generated by PHP Imagick
Duration: 00:00 | DP | 2026-07-05 21:17:00Complete Guide to Installing and Configuring Git Server on Synology NAS: Basic to Advanced
Duration: 00:00 | DP | 2026-07-16 20:39:02Why Do .smbdelete Hidden Files Appear After Deleting on Mac SMB Shares? Causes & Ultimate Solutions
Duration: 00:00 | DP | 2026-06-27 19:10:00Complete Guide to Setting Docker Container Timezone to UTC+8 (Asia/Shanghai)
Duration: 00:00 | DP | 2026-06-30 20:43:30Fixing 'Unable to locate package openjdk-17-jdk' in PHP 8 Docker (Debian Trixie)
Duration: 00:00 | DP | 2026-07-25 09:23:18Docker Compose Advanced: Configuring Static IPs and Cross-Container SOCKS5 Proxies
Duration: 00:00 | DP | 2026-07-26 09:28:30Nginx Reverse Proxy Guide: Elegantly Routing Specific Subdirectories to Docker Containers
Duration: 00:00 | DP | 2026-07-26 21:31:06DevOps Practice: How to Safely Clear Logs of a Running Docker Container?
Duration: 00:00 | DP | 2026-07-27 09:33:42Practical Guide: Translating Complex Docker Compose to Docker Run Commands
Duration: 00:00 | DP | 2026-07-29 09:44:07MySQL TIMESTAMP vs. DATETIME: The Ultimate Guide from DDL Change to Architectural Choice
Duration: 00:00 | DP | 2026-07-31 21:57:08Unlocking the MySQL Self-Referencing FK Trap: Why Does ON UPDATE CASCADE Fail?
Duration: 00:00 | DP | 2026-01-02 08:00:00MySQL Masterclass: How to Set a Custom Starting Value for AUTO_INCREMENT IDs
Duration: 00:00 | DP | 2026-01-03 08:01:17The MySQL DATETIME Trap: Why Inserting Unix Timestamps Directly Can Backfire
Duration: 00:00 | DP | 2026-06-24 10:01:00The MySQL Timestamp Trap: Why Your TIMESTAMP Field Is Auto-Updating and How to Fix It
Duration: 00:00 | DP | 2026-01-04 08:02:34The Ultimate Guide to Docker Cron Logging: Host vs. Container Redirection - Are You Doing It Right?
Duration: 00:00 | DP | 2026-01-05 08:03:52Recommended
Google AdSense Guide for Chinese Creators: Skipping PIN, Wire Transfers, and Hyperwallet Risks
00:00 | 19Compiled by DP@lib00, this guide explores the late...
`self::` vs. `static::` in PHP: A Deep Dive into Late Static Binding
00:00 | 156Explore the crucial difference between PHP's `self...
'claude' Command Not Found on Windows? Master Your npm Global Path Setup
00:00 | 7Encountering the "'command not found'" error in Po...
Mastering Marked.js: A Guide to Adding Custom Classes to Tables (v4+)
00:00 | 127Are you encountering the `[object Object]` error w...