Connect to MySQL and fetch a list of customers asynchronously using C#
In Get() you do not need to wrap the call to GetAllCustomers() into a Task because it's already asynchronous:

public async Task&lt;HttpResponseMessage&gt; Get()
    =&gt; await GetAllCustomers();


There is, however, something else to do:


GetAllCustomers() should be renamed GetAllCustomersAsync() to inform that it's an asynchronous method.
GetAllCustomersAync() should not be responsible to create the HttpResponseMessage because you want to test DB logic separately from controller logic. More on this later.
You do not need to return an HttpResponseMessage, simply return the strongly typed model/view model you're interested to.


In code:

public async Task&lt;DataTable&gt; Get()
    =&gt; await GetAllCustomersAsync();


Now you have to change GetAllCustomersAsync() to match the above.



Outside a fictional example (or an extremely simple application) I'd avoid to directly return DataTable and I'd move to a proper data layer. You usually do not want to handle SQL code directly in your business logic, especially because:


It's error-prone.
UI requirements may change over time but database may be stable.
Database may change over time but UI may be stable.
You do not have any compile-time check.
It's hard to test business logic without a database.




According to usual C# naming conventions local variables are camelCase, Customers should be customers.

You do not need to close a connection if it's wrapped within a using statement, disposing the connection will also close it.



Even assuming you do not return the model type, for example:

public IHttpActionResult Get()


You do not need to go through the ControllerContext.Request.CreateResponse() thing, simply:

public IHttpActionResult Get()
{
    return Ok(new { Customers });
}


In your catch clause ex.Message.ToString(); is doing nothing. If you properly had DB logic in a separate layer (let's say in a class DatabaseServices just to give a name) you may want to:

catch (MySqlException e)
{
    throw new DatabaseException("Cannot read customers", e);
}


Where DatabaseException is a custom exception you use through your data layer. Your controller (simplified without async stuff):

public IHttpActionResult Get()
{
    try
    {
        using (var db = new DatabaseService())
            return Ok(new { Customers = GetAllCustomers() });
    }
    catch (DatabaseException e)
    {
        return InternalServerError(e);
    }
}


Of course in real world there will also be some logging here and there and some logic to recover from known errors...



Jumping back to your query method, it might be simplified little bit:

using (var con = new MySqlConnection("..."))
using (var cmd = new MySqlCommand("SELECT * FROM Customers", con))
{
    try
    {
        await con.OpenAsync();

        var sda = new MySqlDataAdapter(cmd);
        var customers = new DataTable();
        await sda.FillAsync(customers);

        return customers;
    }
    catch (MySqlException ex)
    {
        // ...
    }
}


You do not need to check if connection is closed for a newly created MySqlConnectionObject(), it can't happen and your code wil always work as expected but if it was not the case then you will return an empty DataTable. 

Note that when code will grow and you will probably need a better way to build SQL commands (assuming you won't use an ORM). Very first step is to, at least, move them outside in private const string fields.