خطای ERROR 1040 (HY000): Too many connections یعنی تعداد اتصالهای همزمان MySQL به سقف مجاز رسیده و سرور نمیتواند اتصال معمولی تازهای بپذیرد. راهحل پایدار صرفاً افزایش max_connections نیست: ابتدا باید مشخص کنید اتصالها واقعاً فعالاند، در حالت Sleep انباشته شدهاند، یا برنامه با ساختن اتصالهای بیپایان دچار نشتی (Connection Leak) شده است. سپس بر اساس مصرف RAM و الگوی بار، محدودیت را تنظیم کنید.
خطای Too many connections چه زمانی رخ میدهد؟
این خطا در وبسایت پرترافیک، سرویس API، صف پردازش، Cron و اپلیکیشنی که برای هر درخواست اتصال تازه باز میکند دیده میشود. طبق راهنمای رسمی MySQL، سرور معمولاً یک جایگاه اتصال اضافه برای حساب مدیریتی دارای CONNECTION_ADMIN (یا SUPER قدیمی) کنار میگذارد؛ بنابراین اگر حساب عادی نمیتواند وصل شود، ممکن است حساب مدیر هنوز امکان تشخیص داشته باشد. این قابلیت را به کاربر برنامه ندهید.
مرحله اول: وضعیت اتصالها را بدون تغییر تنظیمات بررسی کنید
در سروری که دسترسی مدیریتی دارید، ابتدا به MySQL متصل شوید. اگر حساب عادی خطای 1040 میدهد، از حساب مدیریتی مجاز استفاده کنید. در Ubuntu بسته به روش احراز هویت، sudo mysql میتواند کار کند.
sudo mysqlاین پرسوجوها سقف فعلی، اتصالهای باز، اوج اتصالهای همزمان از آخرین شروع سرویس و شمار تلاشهای ردشده را نشان میدهند:
SHOW GLOBAL VARIABLES LIKE 'max_connections';
SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected','Threads_running','Max_used_connections','Connection_errors_max_connections');
SHOW FULL PROCESSLIST;Threads_connected شمار اتصالهای باز و Threads_running شمار Threadهای غیرخواب را نشان میدهد؛ این دو یکسان نیستند. Max_used_connections اوج مشاهدهشده از زمان شروع سرویس است و با ریاستارت صفر میشود. اگر Connection_errors_max_connections بالا میرود، درخواستهای اتصال به سقف خوردهاند. دسترسی به همه نشستها در SHOW FULL PROCESSLIST نیازمند مجوز مناسب است.
برای شمارش اتصالها برحسب کاربر و وضعیت، در محیطی که به information_schema.PROCESSLIST دسترسی دارید:
SELECT USER, HOST, COMMAND, COUNT(*) AS connections
FROM information_schema.PROCESSLIST
GROUP BY USER, HOST, COMMAND
ORDER BY connections DESC;اگر دهها اتصال Sleep از یک کاربر یا سرویس دیده میشود، زمان عمر اتصال، تنظیمات Pool و بستن Connection در مسیر خطا را بررسی کنید. Sleep بهتنهایی اثبات نشتی نیست؛ Pool سالم نیز ممکن است اتصال آماده نگه دارد.
مرحله دوم: ریشه مشکل را در اپلیکیشن پیدا کنید
Connection Pool بزرگ یا چند نمونه همزمان
تعداد اتصالهای بالقوه را برآورد کنید: تعداد instance × تعداد worker هر instance × سقف pool هر worker. برای مثال ۴ نمونه با ۸ Worker و Pool برابر ۱۰ میتوانند تا ۳۲۰ اتصال ایجاد کنند؛ این عدد تنها یک ظرفیت نظری است و به رفتار واقعی Pool بستگی دارد. در زمان Autoscaling یا استقرار همزمان نسخه قدیم و جدید، ظرفیت را دوباره حساب کنید.
تراکنش طولانی و اتصالهای بدون آزادسازی
در برنامه، اتصال و Cursor را در بلوکهای finally یا Context Manager آزاد کنید. تراکنش را هنگام درخواست شبکهای طولانی باز نگذارید. در صورت کندی کوئریها، به جای افزایش کورکورانه سقف اتصال، زمان اجرای SQL، ایندکسها و قفلها را بررسی کنید. اگر تازه با MySQL کار میکنید، مقاله آشنایی با پایگاه داده MySQL و کاربرد آن مبانی لازم را توضیح میدهد.
مرحله سوم: افزایش کنترلشده max_connections در صورت نیاز
هشدار: افزایش سقف اتصال میتواند مصرف حافظه و تعداد Threadها را بالا ببرد. پیش از تغییر، RAM آزاد، مصرف فعلی mysqld، محدودیت فایلدسکریپتور و تعداد اتصالهای واقعی را بسنجید. عدد ۳۰۰ در نمونه زیر صرفاً مثال است، نه مقدار پیشنهادی برای همه سرورها.
SHOW GLOBAL VARIABLES LIKE 'max_connections';
SET GLOBAL max_connections = 300;
SHOW GLOBAL VARIABLES LIKE 'max_connections';این تغییر برای اتصالهای جدید اعمال میشود و بهتنهایی پس از Restart پایدار نیست. در MySQL 8، برای تنظیم پایدار از SET PERSIST max_connections = 300; با مجوز لازم استفاده کنید، یا پس از بررسی فایل تنظیمات و شیوه مدیریت سرویس، مقدار max_connections=300 را در بخش [mysqld] فایل پیکربندی معتبر قرار دهید؛ از تعریف دوگانه و متناقض پرهیز کنید. SET PERSIST و فایل پیکربندی را بدون شناخت تقدم تنظیمات با هم ترکیب نکنید.
در هاست اشتراکی معمولاً امکان تغییر سراسری max_connections وجود ندارد؛ در این حالت آمار مصرف و نام برنامه مشکلدار را برای پشتیبانی هاست بفرستید. اگر دیتابیس روی VPS خودمدیریت اجرا میشود و پس از رفع نشتی هنوز به منابع بیشتری نیاز دارید، میتوانید پلنهای سرور مجازی وانسرور را برای مقایسه RAM و CPU بررسی کنید؛ ارتقای VPS بهتنهایی نشتی اتصال را رفع نمیکند.
چطور بفهمیم مشکل برطرف شده است؟
پس از اصلاح Pool یا تنظیمات، همان بار واقعی یا تست کنترلشده را اجرا کنید و مقادیر زیر را در چند بازه زمانی مقایسه کنید:
SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected','Threads_running','Max_used_connections','Connection_errors_max_connections');
SHOW FULL PROCESSLIST;اتصالهای باز باید در محدوده پایدار بمانند، شمار خطاهای تازه ناشی از سقف اتصال افزایش نیابد و برنامه بدون خطای 1040 درخواستها را پاسخ دهد. برای آشنایی با محیط خط فرمان، نمایش فهرست دیتابیسها در MySQL و برای نصب و بررسی سرویس، آموزش نصب MySQL در Ubuntu را ببینید؛ نسخه سیستمعامل آموزش نصب قدیمی است و باید دستورات را با نسخه فعلی خود تطبیق دهید.
Rollback و نکات امنیتی
پیش از تغییر مقدار قبلی max_connections را ثبت کنید. اگر افزایش سقف باعث فشار حافظه یا افت کارایی شد، مقدار قبلی را با SET GLOBAL max_connections = مقدار_قبلی; بازگردانید؛ اگر تغییر پایدار ثبت کردهاید، آن را نیز مطابق روش استفادهشده اصلاح کنید. نشستهای دیگران را با KILL کورکورانه قطع نکنید؛ ابتدا مالک، تراکنش و اثر تجاری را بشناسید. پورت 3306 را برای عیبیابی به اینترنت عمومی باز نکنید و رمز دیتابیس را در خروجی لاگ یا تیکت عمومی قرار ندهید.
پرسشهای رایج
آیا افزایش max_connections همیشه مشکل را حل میکند؟
خیر. اگر برنامه اتصالها را آزاد نکند، با سقف بالاتر هم دوباره به خطا میرسد و ممکن است مصرف RAM بیشتر شود.
چرا Threads_connected زیاد است اما Threads_running کم؟
بخش زیادی از اتصالها ممکن است در حالت Sleep و منتظر درخواست بعدی باشند. این وضعیت را در کنار Pool، زمان بیکاری و تعداد Workerها بررسی کنید.
آیا ریاستارت MySQL راهحل مناسبی است؟
ریاستارت اتصالها را قطع میکند و شاید خطا موقتاً رفع شود، اما درخواستهای فعال مختل میشوند و علت اصلی باقی میماند. در محیط Production فقط با برنامه تغییر و اطلاعرسانی اقدام کنید.
منابع فنی: MySQL 8.4 — Too many connections و MySQL 8.4 — Server System Variables.