After a little astonishment of all the shooting in the dark in this topic, here's my contribution:
The correct minimum set which works in all of the mentioned browsers is the following:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
The PHP way would look like:
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.
header('Expires: 0'); // Proxies.
The Java/Servlet way would look like:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
The ASP.NET way would look like:
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.
The Cache-Control is per the HTTP 1.1 spec for clients (and implicitly required by some browsers next to Expires), the Pragma is per the HTTP 1.0 spec for clients and proxies and Expires is per the HTTP 1.1 spec for clients and proxies.
Other Cache-Control parameters are irrelevant if the abovementioned three are specified. The Last-Modified header is only intersting if you actually want to cache the request.
Note that when you include the headers both programmatically and inside the HTML page as <meta> tags, then the ones which are programmatically specified will get precedence above the ones on the same field in the HTML <meta> tags, because they appears directly in the response headers instead of the response body.