> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL 사용자 관리

> MySQL 사용자를 만들고, 수정하고, 삭제하는 방법: CREATE USER 구문, 권한 수준, GRANT와 REVOKE, MySQL 8.4의 역할, 그리고 최소 권한 모범 사례입니다.

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

MySQL의 접근 제어 모델은 인증(당신이 누구인지)과 권한 부여(무엇을 할 수 있는지)를 분리합니다. 사용자 계정을 만든 다음, 권한을 따로 부여합니다.

## 사용자 만들기

```sql theme={null}
CREATE USER 'alice'@'localhost' IDENTIFIED BY 'strong_password';
```

`@'localhost'` 부분은 호스트 제한입니다. 이 계정은 로컬 머신에서만 연결할 수 있습니다. 흔한 호스트 패턴:

| 호스트 | 의미 |
| :- | :- |
| `'localhost'` | 로컬 소켓 연결만 |
| `'127.0.0.1'` | TCP 루프백만 |
| `'%'` | 모든 호스트(네트워크 접근) |
| `'192.168.1.%'` | 해당 서브넷의 모든 호스트 |
| `'app.example.com'` | 특정 호스트 이름 |

`'alice'@'localhost'`와 `'alice'@'%'`는 사용자 이름이 같더라도 서로 다른 2개의 계정입니다.

## 권한 부여하기

```sql theme={null}
-- Read-only access to one database
GRANT SELECT ON myapp.* TO 'alice'@'localhost';

-- Full access to one database
GRANT ALL PRIVILEGES ON myapp.* TO 'alice'@'localhost';

-- Specific privileges on one table
GRANT SELECT, INSERT, UPDATE ON myapp.orders TO 'alice'@'localhost';

-- Global privilege (all databases)
GRANT PROCESS ON *.* TO 'alice'@'localhost';
```

권한 대상은 `database.table` 표기법을 사용합니다:

* `*.*` — 모든 데이터베이스, 모든 테이블(전역)
* `myapp.*` — `myapp` 데이터베이스의 모든 테이블
* `myapp.orders` — `orders` 테이블만

## 권한 수준

| 수준 | 범위 | 예 |
| :- | :- | :- |
| 전역 | 모든 데이터베이스 | `GRANT RELOAD ON *.*` |
| 데이터베이스 | 데이터베이스 1개 | `GRANT CREATE ON myapp.*` |
| 테이블 | 테이블 1개 | `GRANT SELECT ON myapp.users` |
| 열 | 특정 열 | `GRANT SELECT (id, name) ON myapp.users` |
| 스토어드 루틴 | 프로시저 또는 함수 | `GRANT EXECUTE ON PROCEDURE myapp.get_user` |

흔한 권한:

| 권한 | 허용하는 것 |
| :- | :- |
| `SELECT` | 행 읽기 |
| `INSERT` | 행 삽입 |
| `UPDATE` | 행 수정 |
| `DELETE` | 행 삭제 |
| `CREATE` | 테이블과 데이터베이스 만들기 |
| `DROP` | 테이블과 데이터베이스 삭제 |
| `INDEX` | 인덱스 만들기와 삭제 |
| `ALTER` | 테이블 구조 변경 |
| `EXECUTE` | 스토어드 프로시저와 함수 실행 |
| `PROCESS` | 실행 중인 모든 쿼리 보기(`SHOW PROCESSLIST`) |
| `SUPER` | 제한 무시; 관리 작업 |
| `ALL PRIVILEGES` | 지정한 범위의 모든 권한 |

## 권한 보기

```sql theme={null}
-- Show grants for the current user
SHOW GRANTS;

-- Show grants for a specific user
SHOW GRANTS FOR 'alice'@'localhost';
```

## 권한 회수하기

```sql theme={null}
REVOKE INSERT ON myapp.* FROM 'alice'@'localhost';
REVOKE ALL PRIVILEGES ON myapp.* FROM 'alice'@'localhost';
```

부여한 적 없는 권한을 회수하면 `ERROR 1141: There is no such grant defined for user`를 반환합니다. 사용자는 다른 수준에서 부여된 권한을 유지합니다. `SELECT ON myapp.*`를 회수해도, 따로 부여된 `SELECT ON myapp.orders`는 제거되지 않습니다.

## 비밀번호 변경하기

```sql theme={null}
ALTER USER 'alice'@'localhost' IDENTIFIED BY 'new_password';
```

다음 로그인 시 비밀번호 변경을 강제하려면:

```sql theme={null}
ALTER USER 'alice'@'localhost' PASSWORD EXPIRE;
```

## 역할(MySQL 8.0+)

역할은 이름이 붙은 권한의 모음입니다. 각 사용자에게 개별 권한을 부여하는 대신, 역할을 부여하세요.

```sql theme={null}
-- Create a role
CREATE ROLE 'app_reader', 'app_writer';

-- Grant privileges to the role
GRANT SELECT ON myapp.* TO 'app_reader';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'app_writer';

-- Grant the role to a user
GRANT 'app_reader' TO 'alice'@'localhost';
GRANT 'app_writer' TO 'bob'@'%';
```

사용자는 역할의 권한을 사용하려면 역할을 활성화해야 합니다(또는 기본값으로 설정):

```sql theme={null}
-- Activate in session
SET ROLE 'app_reader';

-- Set default role so it activates automatically on login
SET DEFAULT ROLE 'app_reader' TO 'alice'@'localhost';
```

## 사용자 삭제하기

```sql theme={null}
DROP USER 'alice'@'localhost';
```

사용자를 삭제하면 모든 권한이 자동으로 회수되고 모든 역할에서 제거됩니다. 사용자가 현재 연결되어 있으면, 세션은 끝날 때까지 계속됩니다.

## 최소 권한 모범 사례

각 계정에 필요한 권한만 주세요:

* 애플리케이션 읽기 복제본: `SELECT`만
* 애플리케이션 쓰기 계정: `SELECT`, `INSERT`, `UPDATE`, `DELETE`
* 애플리케이션 스키마 계정(마이그레이션): `CREATE`, `ALTER`, `DROP`, `INDEX` 추가
* DBA 계정: `*.*`에 대한 `ALL PRIVILEGES`
* 애플리케이션 계정에는 절대 `SUPER`나 `ALL`을 부여하지 않기

호스트는 가능한 한 엄격하게 제한하세요. `app.example.com`의 애플리케이션은 `'appuser'@'%'`가 아니라 `'appuser'@'app.example.com'`을 사용해야 합니다.

## 자주 묻는 질문

#### MySQL은 권한을 자동으로 반영하나요?

`CREATE USER`, `GRANT`, `REVOKE`, `ALTER USER`를 통한 모든 변경은 즉시 적용됩니다. `FLUSH PRIVILEGES`는 필요하지 않습니다. `FLUSH PRIVILEGES`는 권한 테이블을 `INSERT`/`UPDATE`로 직접 수정할 때만 필요합니다(그렇게 해서는 안 됩니다).

#### `localhost`와 `127.0.0.1`의 차이는 무엇인가요?

MySQL에서 `localhost`는 네트워크 루프백이 아니라 Unix 소켓 연결(로컬 파일 소켓)을 가리킵니다. `127.0.0.1`은 TCP 루프백입니다. 클라이언트가 같은 머신에서도 TCP로 연결한다면, 호스트 제한으로 `127.0.0.1`을 사용하세요.

## 문제 해결

| 문제 | 해결 방법 |
| :- | :- |
| `ERROR 1045: Access denied for user` | 잘못된 비밀번호, 잘못된 호스트, 또는 계정이 없음. `SELECT user, host FROM mysql.user`로 확인 |
| 사용자가 연결은 되지만 쿼리할 수 없음 | `SHOW GRANTS FOR 'user'@'host'`로 권한을 확인. 권한 수준이 범위(데이터베이스 대 전역)와 일치해야 함 |
| `GRANT`가 `ERROR 1044`로 실패 | 현재 사용자에게 `GRANT OPTION` 권한이 없음. root 또는 `GRANT OPTION`이 있는 사용자로 연결 |
| 사용자를 만들었지만 앱 서버에서 로그인할 수 없음 | `@'host'` 패턴이 앱 서버의 호스트 이름이나 IP와 일치하지 않음. 계정 호스트 패턴을 추가하거나 업데이트 |
| `DROP USER`가 실패 | 정확한 사용자/호스트 조합을 확인: `SELECT user, host FROM mysql.user WHERE user = 'alice'` |

## 함께 보기

* [MySQL 보안 강화](https://villagesql.com/docs/ko/guides/security-hardening.md) — 사용자 권한을 보완하는 서버 수준 보안
* [MySQL INFORMATION\_SCHEMA](https://villagesql.com/docs/ko/guides/information-schema.md) — 명령 뒤에 있는 권한과 메타데이터 쿼리하기
* [흔한 MySQL 오류와 해결 방법](https://villagesql.com/docs/ko/guides/common-mysql-errors.md) — 접근 거부와 다른 흔한 오류 해독하기
* [JWT로 MySQL 사용자를 인증하는 방법](https://villagesql.com/docs/ko/guides/jwt-authentication.md) — 비밀번호 대신 토큰으로 로그인하는 계정


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.