EntityFrameworkCore+MySQL hangs when `Min Pool Size > 0` only on ubuntu/linux

I am currently using net8.0 (though I have also tested this on net6.0), along with the latest versions of EntityFrameworkCore and Pomelo.EntityFrameworkCore.MySql (I have also tested this with MySql.EntityFrameworkCore) and MySQL 8.0.35 (both on docker and installed on host machine). My connection string includes "Min Pool Size=10". The application runs smoothly on various windows platforms: Windows machine, an Ubuntu VM on Windows, a Docker Compose on a Windows machine, and even on Azure. However, when I attempt to run the same application on Ubuntu 22.04 machine, or a Docker Compose on an Ubuntu 22.04 machine, it hangs while trying to establish a connection to the database

When I remove the "Min Pool Size=10" from the connection string, the application runs without any issues in all tested environments. Despite increasing the timeout in the connection string, the application continues to stall if "Min Pool Size > 0" is present.

This is the exception:

app  | Unhandled exception. System.AggregateException: One or more errors occurred. (Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.)
app  |  ---> MySql.Data.MySqlClient.MySqlException (0x80004005): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
app  |  ---> System.TimeoutException: The operation has timed out.
app  |    at MySql.Data.Common.StreamCreator.<>c.<GetTcpStreamAsync>b__8_1()
app  |    at System.Threading.CancellationTokenSource.Invoke(Delegate d, Object state, CancellationTokenSource source)
app  |    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
app  | --- End of stack trace from previous location ---
app  |    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
app  |    at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
app  |    --- End of inner exception stack trace ---
app  |    at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
app  |    at System.Threading.TimerQueueTimer.Fire(Boolean isThreadPool)
app  |    at System.Threading.TimerQueue.FireNextTimers()
app  |    at System.Threading.ThreadPoolWorkQueue.Dispatch()
app  |    at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()

My original application is an ASPNET Core API, but I was able to replicate the issue using a simple console application:

TestApp:

static async Task Main(string[] args)
{
    var envCnx = Environment.GetEnvironmentVariable("CONNECTION_STRING");

    IDbContextFactory dbContextFactory = new AppDbContextFactory(envCnx);

    using var db = await dbContextFactory.CreateDbContextAsync();

    await db.Database.MigrateAsync();

    var name = "User 1";

    if (!await db.Set<UserInfo>().AnyAsync(x => x.Name == name))
    {
        db.Add(new UserInfo() { Id = Guid.NewGuid(), Name = name, CreatedOn = DateTime.Now });

        await db.SaveChangesAsync();
    }
}

AppDbContextFactory:

public interface IDbContextFactory : IDbContextFactory<DbContext>
{
}

public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>, IDbContextFactory<AppDbContext>, IDbContextFactory
{
    private readonly string _cnx;

    public AppDbContextFactory(string cnx)
    {
        _cnx = cnx;
    }

    public AppDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
        string cnx = args.Length > 0 ? args[0] : this._cnx;


#if DEBUG
        optionsBuilder.EnableSensitiveDataLogging();
        optionsBuilder.EnableDetailedErrors();
#endif
        optionsBuilder.UseMySql(cnx, ServerVersion.AutoDetect(cnx), mySqlOpts =>
        {
            mySqlOpts.UseNewtonsoftJson();
            mySqlOpts.MigrationsAssembly(typeof(AppDbContext).Assembly.FullName);
        })
#if DEBUG
            .EnableSensitiveDataLogging()
            .EnableDetailedErrors()
#endif
        ;

        return new AppDbContext(optionsBuilder.Options);
    }

    public AppDbContext GetContext()
    {
        return CreateDbContext([_cnx]);
    }

    public AppDbContext CreateDbContext()
    {
        return GetContext();
    }

    DbContext IDbContextFactory<DbContext>.CreateDbContext()
    {
        return GetContext();
    }
}

AppDbContext:

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<UserInfo>().HasKey(x => x.Id);
        modelBuilder.Entity<UserInfo>().HasIndex(x => x.Id).IsUnique();
        modelBuilder.Entity<UserInfo>().Property(t => t.Id).ValueGeneratedOnAdd();
        modelBuilder.Entity<UserInfo>().Property(x => x.Timestamp).IsRowVersion();
        modelBuilder.Entity<UserInfo>().HasIndex(x => x.Name);
        modelBuilder.Entity<UserInfo>().ToTable("users");
    }
}

UserInfo:

public class UserInfo
{
    [JsonConstructor]
    public UserInfo() { }

    public Guid Id { get; set; }
    public string Name { get; set; }

    public DateTimeOffset CreatedOn { get; set; }

    public DateTime Timestamp { get; set; }
}

Dockerfile:

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
USER app
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ConsoleTestApp/ConsoleTestApp.csproj", "ConsoleTestApp/"]
RUN dotnet restore "./ConsoleTestApp/ConsoleTestApp.csproj"
COPY . .
WORKDIR "/src/ConsoleTestApp"
RUN dotnet build "./ConsoleTestApp.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./ConsoleTestApp.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ConsoleTestApp.dll"]

docker-compose.yml

version: "3.3"
name: "test-app"

services:

  app:
    image: console-app:latest
    container_name: console-app
    depends_on:
      - mysql
    environment:
      # CONNECTION_STRING: server=mysql,3306;user=root;password=2YSCK+fktPRGOi5omfRjCAP_am9+3r;database=test_db
      CONNECTION_STRING: server=mysql,3306;user=root;password=2YSCK+fktPRGOi5omfRjCAP_am9+3r;database=test_db;Min Pool Size=10;Connect Timeout=600

  mysql:
    container_name: db
    image: mysql:8.0.35
    cap_add:
      - SYS_NICE
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: 2YSCK+fktPRGOi5omfRjCAP_am9+3r
      MYSQL_DATABASE: test_db

project structure:

.
├── ConsoleTestApp
│   ├── ConsoleTestApp.csproj
│   ├── Data
│   │   ├── AppDbContext.cs
│   │   ├── AppDbContextFactory.cs
│   │   ├── Migrations
│   │   │   ├── 20240523164903_InitialMigration.Designer.cs
│   │   │   ├── 20240523164903_InitialMigration.cs
│   │   │   └── AppDbContextModelSnapshot.cs
│   │   └── UserInfo.cs
│   ├── Program.cs
│   └── Properties
│       └── launchSettings.json
├── ConsoleTestApp.sln
├── Dockerfile
└── docker-compose.yml

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật