In a medium saucepan, melt the butter completely over medium heat. Once the butter is melted and bubbling slightly, sprinkle in the flour. Immediately begin whisking continuously. Cook the mixture, still whisking, for about 1 to 2 minutes. The mixture, known as a roux, will transform from a clumpy paste into a smoother, slightly golden base. This essential step cooks out the raw flour taste and is the key to a smooth, lump-free gravy.
To ensure a perfectly smooth consistency, temporarily remove the pan from the heat. Slowly drizzle in about ¼ cup of the milk while whisking constantly and vigorously until the mixture is completely smooth. It will thicken up quickly into a paste. Add another ¼ cup of milk and continue to whisk until it is fully incorporated and smooth again. Once the base is smooth, slowly pour in the remaining 1 ½ cups of milk in a steady stream, whisking continuously. Stir in the salt and pepper.
Return the saucepan to the stove over medium heat. Bring the mixture to a gentle simmer, but do not let it come to a rolling boil. Continue to stir or whisk frequently to prevent lumps from forming and to keep the bottom from scorching. As it simmers, the gravy will thicken to a glossy, velvety texture, which should take about 2–3 minutes. You'll know it's ready when it coats the back of a spoon.
The gravy will continue to thicken as it cools. For a thinner consistency, gradually whisk in more milk (up to 1 additional cup) until it reaches your desired thickness. Let it heat through for another minute without boiling.
Taste the finished gravy and adjust the seasoning if needed, adding more salt or pepper. If any lumps have managed to form, you can easily strain the gravy through a fine-mesh sieve for the smoothest possible texture. Serve immediately over biscuits, mashed potatoes, fried chicken, or any dish that calls for a rich, creamy sauce.