MySQL 데이터 소스 문제 해결
MySQL 데이터 소스 문제 해결 (Troubleshoot MySQL data source issues)
이 문서는 Grafana에서 MySQL 데이터 소스를 구성하거나 사용할 때 겪을 수 있는 일반적인 문제에 대한 해결책을 제공해요. 연결·인증·쿼리·성능·기타 문제를 다룹니다.
출처: 문서
본문
연결 오류
서버에 연결할 수 없음 — 오류: "dial tcp: connection refused" 또는 "Could not connect to MySQL" 원인: Grafana가 MySQL 서버와 네트워크 연결을 설정할 수 없어요. 해결:
- MySQL 서버가 실행 중이고 접근 가능한지 확인해요.
- 데이터 소스 구성의 호스트와 포트가 올바른지 확인해요. 기본 MySQL 포트는
3306이에요. - Grafana와 MySQL 사이를 막는 방화벽 규칙이 없는지 확인해요.
- MySQL 구성에서
bind-address설정을 확인해 원격 연결이 허용되는지 확인해요. - Grafana Cloud라면 MySQL 인스턴스가 공개적으로 접근 가능하지 않을 때 Private data source connect를 구성했는지 확인해요.
연결 타임아웃 — 오류: "Connection timed out" 또는 "I/O timeout"
원인: 응답을 받기 전에 MySQL 연결이 타임아웃됐어요.
해결: Grafana-MySQL 간 네트워크 지연을 확인하고, MySQL이 과부하나 성능 문제를 겪지 않는지 확인하며, 로드 밸런서·프록시 같은 네트워크 장치가 연결을 타임아웃시키는지 확인하고, 유휴 중 연결이 타임아웃되면 MySQL의 wait_timeout 설정을 늘려요.
TLS/SSL 연결 실패 — MySQL 서버가 암호화 연결을 요구하지만 Grafana 데이터 소스가 일치하지 않을 때 발생해요. 일반 오류: "TLS handshake failed", "x509: certificate verify failed", "Connection refused", "Error 3159: Connections using insecure transport are prohibited while --require_secure_transport=ON".
| Cause | Solution |
|---|---|
| MySQL에 require_secure_transport가 켜져 있거나 AWS RDS Proxy가 TLS 강제 | 데이터 소스 구성에서 With CA Cert 또는 Skip TLS Verification 활성화. 어느 쪽이든 TLS 연결을 수립함. |
| 자체 서명 또는 비공개 CA 인증서를 신뢰하지 않음 | With CA Cert 활성화하고 TLS/SSL Root Certificate 아래에 루트 인증서 제공. |
| 인증서 만료 또는 호스트 이름 불일치 | 인증서 갱신, 또는 개발 환경에서만 Skip TLS Verification 활성화. |
| AWS RDS 또는 RDS Proxy에 대해 TLS 핸드셰이크 실패 | With CA Cert 활성화한 채 TLS/SSL Root Certificate 아래에 Amazon RDS 루트 CA 인증서 제공. |
| 조직이 상호 TLS(mTLS) 요구 | Use TLS Client Auth 활성화하고 CA 인증서와 함께 클라이언트 인증서·키 제공. |
Note: Skip TLS Verification과 With CA Cert는 모두 암호화 연결을 수립해요. 상호 TLS가 요구되지 않으면 Use TLS Client Auth가 필요 없어요. 대부분의 AWS RDS/RDS Proxy 연결에선 Amazon 루트 CA를 사용한 With CA Cert가 충분해요.
프로비저닝된 데이터 소스에 TLS 활성화:
jsonData:
tlsAuthWithCACert: true
secureJsonData:
tlsCACert: ${CA_CERT}
인증서 검증을 건너뛰려면:
jsonData:
tlsSkipVerify: true
모든 TLS 프로비저닝 옵션은 "TLS provisioning examples" 문서를 참고하세요.
피어에 의한 연결 리셋 — 오류: "Connection reset by peer" 또는 "EOF"
원인: MySQL 서버가 예기치 않게 연결을 닫았어요.
해결: max_connections가 초과되지 않는지, wait_timeout과 interactive_timeout이 너무 낮지 않은지 확인하고, Grafana 데이터 소스 구성의 Max lifetime을 MySQL wait_timeout보다 낮게 설정하며, MySQL 서버 로그를 확인해요.
인증 오류
사용자 접근 거부 — 오류: "Access denied for user 'username'@'host'" 또는 "Authentication failed" 원인: 자격 증명이 잘못됐거나 사용자가 Grafana 서버 호스트에서 연결할 권한이 없어요. 해결: 사용자 이름·비밀번호 확인, MySQL에 사용자가 존재하고 활성화됐는지 확인, 사용자가 Grafana 서버 IP에서 연결할 권한이 있는지 확인해요:
SELECT user, host FROM mysql.user WHERE user = 'your_user';
필요하면 Grafana 서버에서 연결할 수 있는 사용자 생성:
CREATE USER 'grafana'@'grafana_server_ip' IDENTIFIED BY 'password';
mysql_native_password 인증 플러그인을 쓰면 서버에서 활성화됐는지 확인해요.
데이터베이스 접근 불가 — 오류: "Access denied for user 'username'@'host' to database 'dbname'" 원인: 인증된 사용자가 지정한 데이터베이스에 접근할 권한이 없어요. 해결: 데이터베이스 이름 확인, 사용자에게 권한 부여:
GRANT SELECT ON your_database.* TO 'grafana'@'grafana_server_ip';
FLUSH PRIVILEGES;
프로덕션에서는 특정 테이블에만 권한 부여:
GRANT SELECT ON your_database.your_table TO 'grafana'@'grafana_server_ip';
PAM 인증 문제 — 오류: "Authentication plugin 'auth_pam' cannot be loaded" 또는 cleartext 비밀번호 오류 원인: PAM 인증은 cleartext 비밀번호 전송을 요구해요. 해결: 데이터 소스 구성에서 Allow Cleartext Passwords를 활성화하고, cleartext 비밀번호 사용 시 TLS로 전송을 보호하며, PAM 플러그인이 MySQL 서버에 올바르게 설치·구성됐는지 확인해요.
쿼리 오류
time 컬럼을 찾을 수 없거나 유효하지 않음 — 시계열 시각화에 데이터가 없음
원인: 쿼리가 시계열 시각화에 적합한 time 컬럼을 반환하지 않아요.
해결: Time series 포맷 사용 시 쿼리에 time이라는 컬럼을 포함하고, $__time() 매크로로 날짜 컬럼을 변환하며 ($__time(your_date_column)), time 컬럼이 유효한 MySQL 날짜/시간 타입(DATETIME, TIMESTAMP, DATE)이거나 Unix epoch 값을 포함하며, ORDER BY로 time 컬럼 기준 정렬했는지 확인해요.
매크로 확장 오류 — "Error parsing query" 또는 매크로가 확장되지 않음
원인: Grafana 매크로를 잘못 사용했어요.
해결: $__timeFilter(column)(잘못된 $_timeFilter(column)이 아닌)처럼 매크로 문법을 확인하고, 매크로에 전달한 컬럼 이름이 테이블에 존재하는지 확인하며, 쿼리 실행 후 Generated SQL을 클릭해 확장된 쿼리를 확인하고, 예약어·특수 문자 컬럼에 백틱을 사용해요 ($__timeFilter(\time-column`)`).
따옴표 문자열의 # 문자로 인한 쿼리 오류 — 문자열 값에 #이 있으면 예기치 않은 결과·오류
원인: Grafana 13.0 이전 버전의 SQL 주석 제거 로직이 따옴표 문자열 안의 #(예: WHERE color = '#FF0000')을 주석 구분자로 잘못 취급해 나머지 줄을 제거했어요.
해결: 따옴표 안 #을 보존하는 Grafana 13.0 이상으로 업그레이드하거나, 이전 버전에서는 문자열 리터럴에서 #을 피하기 위해 CONCAT 함수나 16진수 리터럴을 사용해요.
시간대 및 시간 이동 문제
원인: 시계열 데이터가 이동해 보이거나 예상 시간과 정렬되지 않아요.
해결: 타임스탬프를 UTC로 저장하고, 시간 매크로($__time, $__timeFilter 등)는 항상 UTC 값으로 확장되며, 데이터 소스 구성의 Session Timezone을 데이터 시간대와 일치시키거나 UTC에 +00:00을 사용하고, 로컬 시간으로 저장했다면 쿼리에서 UTC로 변환해요:
SELECT
CONVERT_TZ(your_datetime_column, 'Your/Timezone', 'UTC') AS time,
value
FROM your_table
쿼리가 너무 많은 행 반환 — "Result set too large" 또는 브라우저 응답 없음
해결: $__timeFilter(column)으로 대시보드 시간 범위로 데이터를 제한하고, 원시 행 대신 GROUP BY와 함께 집계(AVG, SUM, COUNT)를 사용하며, LIMIT 절로 결과를 제한하고(SELECT ... LIMIT 1000), $__timeGroup() 매크로로 시간 간격으로 집계해요.
SQL 문법 오류 — "You have an error in your SQL syntax"
해결: 누락되거나 추가된 쉼표·괄호·따옴표를 확인하고, 식별자로 쓰인 예약어를 백틱으로 감싸고(table, select), 템플릿 변수 문법($variable 또는 ${variable})을 확인하며, Grafana 특유 문제를 분리하기 위해 MySQL 클라이언트에서 직접 쿼리를 테스트해요.
필드 목록의 알 수 없는 컬럼 — "Unknown column 'column_name' in 'field list'"
해결: 컬럼 이름 철자 확인, 테이블에 컬럼이 존재하는지 확인, 특수 문자·공백이 있으면 백틱(column-name)으로 감싸고, 전체 테이블 경로 없이 컬럼을 참조한다면 올바른 데이터베이스가 선택됐는지 확인해요.
비표준 문자열 컬럼 타입에서 CASE 표현식 실패 — Grafana에서 오류지만 다른 MySQL 클라이언트에서는 동작
원인: Grafana의 Go MySQL 드라이버가 CASE 표현식의 모든 MySQL 문자열 하위 타입(ENUM, SET, TINYTEXT, MEDIUMTEXT 등)을 처리하지 못해요.
해결: CASE 표현식 전에 CAST()로 컬럼을 CHAR로 정규화해요:
SELECT
CASE WHEN CAST(status_column AS CHAR) = 'active' THEN 1 ELSE 0 END AS is_active
FROM my_table
성능 문제
느린 쿼리 실행 — 쿼리가 오래 걸려요. 해결: 데이터 양을 줄이려면 대시보드 시간 범위를 줄이고, WHERE 절과 시간 필터에 쓰는 컬럼에 인덱스를 추가하며:
CREATE INDEX idx_time ON your_table(time_column);
개별 행 대신 집계를 사용하고, Min time interval 설정을 늘려 데이터 포인트 수를 줄이며, 병목을 찾기 위해 EXPLAIN으로 실행 계획을 검토해요:
EXPLAIN SELECT * FROM your_table WHERE time_column > NOW() - INTERVAL 1 HOUR;
연결 풀 고갈 — "Too many connections" 또는 "Connection pool exhausted"
원인: 데이터베이스에 대한 동시 연결이 너무 많아요.
해결: 데이터 소스 구성의 Max open connection 제한을 늘리고, Auto(max idle)를 활성화하며, 같은 데이터 소스를 동시에 쿼리하는 패널 수를 줄이고, 연결을 잡고 있을 수 있는 장기 실행 쿼리를 확인하며, 필요시 MySQL의 max_connections를 늘려요:
SHOW VARIABLES LIKE 'max_connections';
SET GLOBAL max_connections = 200;
쿼리 타임아웃 — "Query execution was interrupted" 또는 "Lock wait timeout exceeded" 해결: 적절한 인덱스를 추가해 쿼리를 최적화하고, 시간 범위를 좁혀 쿼리되는 데이터 양을 줄이며, 결과 집합 크기를 줄이려면 집계를 사용하고, 쿼리를 막는 테이블 잠금이 있는지 확인해요.
기타 일반 문제
템플릿 변수 쿼리 실패 — 변수 쿼리가 예기치 않은 결과나 오류를 반환해요. 해결: 변수 쿼리가 단일 컬럼을 반환하는 유효한 SQL인지 확인하고, 데이터 소스 연결이 동작하는지 확인하며, 사용자가 변수 쿼리의 테이블에 접근 권한이 있는지 확인하고, 변수 쿼리로 쓰기 전에 쿼리 편집기에서 테스트해요.
데이터가 올바르지 않거나 정렬이 어긋남
해결: 명시적 컬럼 별칭(SELECT value AS metric)으로 일관된 이름을 사용하고, 숫자 컬럼이 문자열이 아니라 실제 숫자 타입인지 확인하며, 집계에 영향을 줄 NULL 값을 확인하고, 누락된 데이터 포인트를 처리하려면 $__timeGroup() 매크로의 FILL 옵션을 사용해요.
데이터베이스 또는 테이블 이름의 특수 문자 — 예약어나 특수 문자가 있는 테이블·데이터베이스에서 쿼리 실패
해결: 특수 문자가 있는 식별자를 백틱(my-database`.`my-table)으로 감싸고, 쿼리 편집기는 선택에 대해 자동 처리하지만 수동 쿼리에는 백틱이 필요하며, 가능하면 식별자로 예약어를 피해요.
프로비저닝된 데이터 소스에서 쿼리 캐싱 활성화 불가 — YAML로 프로비저닝하면 UI의 쿼리 캐싱 토글이 회색으로 표시돼요. YAML 프로비저닝은 현재 캐싱 구성 설정을 지원하지 않아요. 해결: Grafana HTTP API로 캐싱이 활성화된 데이터 소스를 PUT 요청으로 업데이트해요:
curl -X PUT -H "Content-Type: application/json" \
-H "Authorization: Bearer ***" \
"https://<GRAFANA_URL>/api/datasources/<DATASOURCE_ID>" \
-d '{
"jsonData": {
"queryCachingTTL": 300
}
}'
<API_TOKEN>을 유효한 Grafana API 토큰, <GRAFANA_URL>을 Grafana 인스턴스 URL, <DATASOURCE_ID>를 데이터 소스의 숫자 ID로 바꾸세요. queryCachingTTL은 원하는 캐시 지속 시간(초)으로 설정해요. 데이터 소스 ID는 GET /api/datasources/name/<DATA_SOURCE_NAME>로 얻어요.
Note: 쿼리 캐싱은 Grafana Enterprise와 Grafana Cloud에서 사용할 수 있어요. 자세한 내용은 "Query and resource caching" 문서를 참고하세요.
예기치 않은 오류 발생 — "An unexpected error happened" 해결: Grafana 서버 로그에서 자세한 내용을 확인하고, 모든 데이터 소스 구성 설정이 올바른지 확인하며, Save & test 버튼으로 연결을 테스트하고, MySQL 서버가 접근 가능하고 쿼리에 응답하는지 확인하며, Grafana Cloud 고객은 지원에 문의해요.
추가 도움
- Grafana 커뮤니티 포럼, Grafana GitHub issues, Grafana 디버그 로깅 활성화, MySQL 오류 로그 확인, Enterprise·Cloud 고객은 Grafana Support에 문의해요.
문제 보고 시 포함할 내용:
- Grafana 버전
- MySQL 데이터 소스 플러그인 버전(Administration > Plugins 페이지에서 확인. 플러그인은 Grafana 릴리스와 별개로 업데이트됨)
- MySQL 버전
- 오류 메시지(민감 정보 삭제)
- 재현 단계
- 관련 쿼리 예제(민감 데이터 삭제)