Cook diced bacon in a large Dutch oven over medium heat for 8-10 minutes, until crispy and deep brown. Remove 1/4 cup of bacon bits with a slotted spoon and set aside for garnish.
Leave 2 tablespoons of bacon fat in the pot, then add diced onion. Cook for 5-6 minutes until soft and translucent. Add minced garlic and cook for another 30 seconds, being careful not to burn it.
Push the onion mixture to one side and add butter. Once melted, sprinkle in flour and whisk together. Stir for 2 minutes until the roux is light golden and smells nutty.
Slowly pour in chicken broth while whisking to avoid lumps. Add cubed potatoes, salt, black pepper, and cayenne. Bring to a gentle boil, reduce heat, and simmer uncovered for 15-20 minutes until potatoes are fork-tender but still hold shape.
Add heavy cream and milk, then simmer gently for another 5 minutes without boiling.
Use a potato masher to gently mash the soup, breaking up some potatoes but leaving chunks for texture. The soup should be creamy with defined pieces of potato.
Turn off heat and stir in shredded cheddar cheese and sour cream until the cheese melts completely. Taste and adjust seasoning with more salt if needed.
Ladle soup into bowls and top with crispy bacon bits, sliced green onions, and extra cheese, if desired. The soup should be thick enough to support the toppings without sinking.